| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936 | #!/usr/bin/env perl# Copyright (C) 2007,2008,2009,2010,2011,2012,2013,2014 Ole Tange and# Free Software Foundation, Inc.## This program is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 3 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful, but# WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU# General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, see <http://www.gnu.org/licenses/># or write to the Free Software Foundation, Inc., 51 Franklin St,# Fifth Floor, Boston, MA 02110-1301 USA# open3 used in Job::startuse IPC::Open3;# &WNOHANG used in reaperuse POSIX qw(:sys_wait_h setsid ceil :errno_h);# gensym used in Job::startuse Symbol qw(gensym);# tempfile used in Job::startuse File::Temp qw(tempfile tempdir);# mkpath used in openresultsfileuse File::Path;# GetOptions used in get_options_from_arrayuse Getopt::Long;# Used to ensure code qualityuse strict;use File::Basename;if(not $ENV{HOME}) {    # $ENV{HOME} is sometimes not set if called from PHP    ::warning("\$HOME not set. Using /tmp\n");    $ENV{HOME} = "/tmp";}save_stdin_stdout_stderr();save_original_signal_handler();parse_options();::debug("init", "Open file descriptors: ", join(" ",keys %Global::fd), "\n");my $number_of_args;if($Global::max_number_of_args) {    $number_of_args=$Global::max_number_of_args;} elsif ($opt::X or $opt::m or $opt::xargs) {    $number_of_args = undef;} else {    $number_of_args = 1;}my @command;@command = @ARGV;my @fhlist;if($opt::pipepart) {    @fhlist = map { open_or_exit($_) } "/dev/null";} else {    @fhlist = map { open_or_exit($_) } @opt::a;    if(not @fhlist and not $opt::pipe) {	@fhlist = (*STDIN);    }}if($opt::skip_first_line) {    # Skip the first line for the first file handle    my $fh = $fhlist[0];    <$fh>;}if($opt::header and not $opt::pipe) {    my $fh = $fhlist[0];    # split with colsep or \t    # $header force $colsep = \t if undef?    my $delimiter = $opt::colsep;    $delimiter ||= "\$";    my $id = 1;    for my $fh (@fhlist) {	my $line = <$fh>;	chomp($line);	::debug("init", "Delimiter: '$delimiter'");	for my $s (split /$delimiter/o, $line) {	    ::debug("init", "Colname: '$s'");	    # Replace {colname} with {2}	    # TODO accept configurable short hands	    # TODO how to deal with headers in {=...=}	    for(@command) {	      s:\{$s(|/|//|\.|/\.)\}:\{$id$1\}:g;	    }	    $Global::input_source_header{$id} = $s;	    $id++;	}    }} else {    my $id = 1;    for my $fh (@fhlist) {	$Global::input_source_header{$id} = $id;	$id++;    }}if($opt::filter_hosts and (@opt::sshlogin or @opt::sshloginfile)) {    # Parallel check all hosts are up. Remove hosts that are down    filter_hosts();}if($opt::nonall or $opt::onall) {    onall(@command);    wait_and_exit(min(undef_as_zero($Global::exitstatus),254));}# TODO --transfer foo/./bar --cleanup# multiple --transfer and --basefile with different /./$Global::JobQueue = JobQueue->new(    \@command,\@fhlist,$Global::ContextReplace,$number_of_args,\@Global::ret_files);if($opt::eta or $opt::bar) {    # Count the number of jobs before starting any    $Global::JobQueue->total_jobs();}if($opt::pipepart) {    @Global::cat_partials = map { pipe_part_files($_) } @opt::a;    # Unget the command as many times as there are parts    $Global::JobQueue->{'commandlinequeue'}->unget(	map { $Global::JobQueue->{'commandlinequeue'}->get() } @Global::cat_partials	);}for my $sshlogin (values %Global::host) {    $sshlogin->max_jobs_running();}init_run_jobs();my $sem;if($Global::semaphore) {    $sem = acquire_semaphore();}$SIG{TERM} = \&start_no_new_jobs;start_more_jobs();if(not $opt::pipepart) {    if($opt::pipe) {	spreadstdin();    }}::debug("init", "Start draining\n");drain_job_queue();::debug("init", "Done draining\n");reaper();::debug("init", "Done reaping\n");if($opt::pipe and @opt::a) {    for my $job (@Global::tee_jobs) {	unlink $job->fh(2,"name");	$job->set_fh(2,"name","");	$job->print();	unlink $job->fh(1,"name");    }}::debug("init", "Cleaning\n");cleanup();if($Global::semaphore) {    $sem->release();}for(keys %Global::sshmaster) {    kill "TERM", $_;}::debug("init", "Halt\n");if($opt::halt_on_error) {    wait_and_exit($Global::halt_on_error_exitstatus);} else {    wait_and_exit(min(undef_as_zero($Global::exitstatus),254));}sub __PIPE_MODE__ {}sub pipe_part_files {    # Input:    #   $file = the file to read    # Returns:    #   @commands that will cat_partial each part    my ($file) = @_;    my $buf = "";    my $header = find_header(\$buf,open_or_exit($file));    # find positions    my @pos = find_split_positions($file,$opt::blocksize,length $header);    # Make @cat_partials    my @cat_partials = ();    for(my $i=0; $i<$#pos; $i++) {	push @cat_partials, cat_partial($file, 0, length($header), $pos[$i], $pos[$i+1]);    }    # Remote exec should look like:    #  ssh -oLogLevel=quiet lo  'eval `echo $SHELL | grep "/t\{0,1\}csh" > /dev/null  && echo setenv PARALLEL_SEQ '$PARALLEL_SEQ'\;  setenv PARALLEL_PID '$PARALLEL_PID'  || echo PARALLEL_SEQ='$PARALLEL_SEQ'\;export PARALLEL_SEQ\;  PARALLEL_PID='$PARALLEL_PID'\;export PARALLEL_PID` ;'  tty\ \>/dev/null\ \&\&\ stty\ isig\ -onlcr\ -echo\;echo\ \$SHELL\ \|\ grep\ \"/t\\\{0,1\\\}csh\"\ \>\ /dev/null\ \&\&\ setenv\ FOO\ /tmp/foo\ \|\|\ export\ FOO=/tmp/foo\; \(wc\ -\ \$FOO\)    # ssh -tt not allowed. Remote will die due to broken pipe anyway.    # TODO test remote with --fifo / --cat    return @cat_partials;}sub find_header {    # Input:    #   $buf_ref = reference to read-in buffer    #   $fh = filehandle to read from    # Uses:    #   $opt::header    #   $opt::blocksize    # Returns:    #   $header string    my ($buf_ref, $fh) = @_;    my $header = "";    if($opt::header) {	if($opt::header eq ":") { $opt::header = "(.*\n)"; }	# Number = number of lines	$opt::header =~ s/^(\d+)$/"(.*\n)"x$1/e;	while(read($fh,substr($$buf_ref,length $$buf_ref,0),$opt::blocksize)) {	    if($$buf_ref=~s/^($opt::header)//) {		$header = $1;		last;	    }	}    }    return $header;}sub find_split_positions {    # Input:    #   $file = the file to read    #   $block = (minimal) --block-size of each chunk    #   $headerlen = length of header to be skipped    # Uses:    #   $opt::recstart    #   $opt::recend    # Returns:    #   @positions of block start/end    my($file, $block, $headerlen) = @_;    my $size = -s $file;    $block = int $block;    # The optimal dd blocksize for mint, redhat, solaris, openbsd = 2^17..2^20    # The optimal dd blocksize for freebsd = 2^15..2^17    my $dd_block_size = 131072; # 2^17    my @pos;    my ($recstart,$recend) = recstartrecend();    my $recendrecstart = $recend.$recstart;    my $fh = ::open_or_exit($file);    push(@pos,$headerlen);    for(my $pos = $block+$headerlen; $pos < $size; $pos += $block) {	my $buf;	seek($fh, $pos, 0) || die;	while(read($fh,substr($buf,length $buf,0),$dd_block_size)) {	    if($opt::regexp) {		# If match /$recend$recstart/ => Record position		if($buf =~ /(.*$recend)$recstart/os) {		    my $i = length($1);		    push(@pos,$pos+$i);		    # Start looking for next record _after_ this match		    $pos += $i;		    last;		}	    } else {		# If match $recend$recstart => Record position		my $i = index($buf,$recendrecstart);		if($i != -1) {		    push(@pos,$pos+$i);		    # Start looking for next record _after_ this match		    $pos += $i;		    last;		}	    }	}    }    push(@pos,$size);    close $fh;    return @pos;}sub cat_partial {    # Input:    #   $file = the file to read    #   ($start, $end, [$start2, $end2, ...]) = start byte, end byte    # Returns:    #   Efficient perl command to copy $start..$end, $start2..$end2, ... to stdout    my($file, @start_end) = @_;    my($start, $i);    # Convert start_end to start_len    my @start_len = map { if(++$i % 2) { $start = $_; } else { $_-$start } } @start_end;    return "<". shell_quote_scalar($file) .	q{ perl -e 'while(@ARGV) { sysseek(STDIN,shift,0) || die; $left = shift; while($read = sysread(STDIN,$buf, ($left > 32768 ? 32768 : $left))){ $left -= $read; syswrite(STDOUT,$buf); } }' } .	" @start_len";}sub spreadstdin {    # read a record    # Spawn a job and print the record to it.    # Uses:    #   $opt::blocksize    #   STDIN    #   $opr::r    #   $Global::max_lines    #   $Global::max_number_of_args    #   $opt::regexp    #   $Global::start_no_new_jobs    #   $opt::roundrobin    #   %Global::running    my $buf = "";    my ($recstart,$recend) = recstartrecend();    my $recendrecstart = $recend.$recstart;    my $chunk_number = 1;    my $one_time_through;    my $blocksize = $opt::blocksize;    my $in = *STDIN;    my $header = find_header(\$buf,$in);    while(1) {      my $anything_written = 0;      if(not read($in,substr($buf,length $buf,0),$blocksize)) {	  # End-of-file	  $chunk_number != 1 and last;	  # Force the while-loop once if everything was read by header reading	  $one_time_through++ and last;      }      if($opt::r) {	  # Remove empty lines	  $buf =~ s/^\s*\n//gm;	  if(length $buf == 0) {	      next;	  }      }      if($Global::max_lines and not $Global::max_number_of_args) {	  # Read n-line records	  my $n_lines = $buf =~ tr/\n/\n/;	  my $last_newline_pos = rindex($buf,"\n");	  while($n_lines % $Global::max_lines) {	      $n_lines--;	      $last_newline_pos = rindex($buf,"\n",$last_newline_pos-1);	  }	  # Chop at $last_newline_pos as that is where n-line record ends	  $anything_written +=	      write_record_to_pipe($chunk_number++,\$header,\$buf,				   $recstart,$recend,$last_newline_pos+1);	  substr($buf,0,$last_newline_pos+1) = "";      } elsif($opt::regexp) {	  if($Global::max_number_of_args) {	      # -N => (start..*?end){n}	      # -L -N => (start..*?end){n*l}	      my $read_n_lines = $Global::max_number_of_args * ($Global::max_lines || 1);	      while($buf =~ s/((?:$recstart.*?$recend){$read_n_lines})($recstart.*)$/$2/os) {		  # Copy to modifiable variable		  my $b = $1;		  $anything_written +=		      write_record_to_pipe($chunk_number++,\$header,\$b,					   $recstart,$recend,length $1);	      }	  } else {	      # Find the last recend-recstart in $buf	      if($buf =~ s/(.*$recend)($recstart.*?)$/$2/os) {		  # Copy to modifiable variable		  my $b = $1;		  $anything_written +=		      write_record_to_pipe($chunk_number++,\$header,\$b,					   $recstart,$recend,length $1);	      }	  }      } else {	  if($Global::max_number_of_args) {	      # -N => (start..*?end){n}	      my $i = 0;	      my $read_n_lines = $Global::max_number_of_args * ($Global::max_lines || 1);	      while(($i = nindex(\$buf,$recendrecstart,$read_n_lines)) != -1) {		  $i += length $recend; # find the actual splitting location		  $anything_written +=		      write_record_to_pipe($chunk_number++,\$header,\$buf,					   $recstart,$recend,$i);		  substr($buf,0,$i) = "";	      }	  } else {	      # Find the last recend-recstart in $buf	      my $i = rindex($buf,$recendrecstart);	      if($i != -1) {		  $i += length $recend; # find the actual splitting location		  $anything_written +=		      write_record_to_pipe($chunk_number++,\$header,\$buf,					   $recstart,$recend,$i);		  substr($buf,0,$i) = "";	      }	  }      }      if(not $anything_written and not eof($in)) {	  # Nothing was written - maybe the block size < record size?	  # Increase blocksize exponentially	  my $old_blocksize = $blocksize;	  $blocksize = ceil($blocksize * 1.3 + 1);	  ::warning("A record was longer than $old_blocksize. " .		    "Increasing to --blocksize $blocksize\n");      }    }    ::debug("init", "Done reading input\n");    # If there is anything left in the buffer write it    substr($buf,0,0) = "";    write_record_to_pipe($chunk_number++,\$header,\$buf,$recstart,$recend,length $buf);    $Global::start_no_new_jobs ||= 1;    if($opt::roundrobin) {	for my $job (values %Global::running) {	    close $job->fh(0,"w");	}	my %incomplete_jobs = %Global::running;	my $sleep = 1;	while(keys %incomplete_jobs) {	    my $something_written = 0;	    for my $pid (keys %incomplete_jobs) {		my $job = $incomplete_jobs{$pid};		if($job->stdin_buffer_length()) {		    $something_written += $job->non_block_write();		} else {		    delete $incomplete_jobs{$pid}		}	    }	    if($something_written) {		$sleep = $sleep/2+0.001;	    }	    $sleep = ::reap_usleep($sleep);	}    }}sub recstartrecend {    # Uses:    #   $opt::recstart    #   $opt::recend    # Returns:    #   $recstart,$recend with default values and regexp conversion    my($recstart,$recend);    if(defined($opt::recstart) and defined($opt::recend)) {	# If both --recstart and --recend is given then both must match	$recstart = $opt::recstart;	$recend = $opt::recend;    } elsif(defined($opt::recstart)) {	# If --recstart is given it must match start of record	$recstart = $opt::recstart;	$recend = "";    } elsif(defined($opt::recend)) {	# If --recend is given then it must match end of record	$recstart = "";	$recend = $opt::recend;    }    if($opt::regexp) {	# If $recstart/$recend contains '|' this should only apply to the regexp	$recstart = "(?:".$recstart.")";	$recend = "(?:".$recend.")";    } else {	# $recstart/$recend = printf strings (\n)	$recstart =~ s/\\([0rnt\'\"\\])/"qq|\\$1|"/gee;	$recend =~ s/\\([0rnt\'\"\\])/"qq|\\$1|"/gee;    }    return ($recstart,$recend);}sub nindex {    # See if string is in buffer N times    # Returns:    #   the position where the Nth copy is found    my ($buf_ref, $str, $n) = @_;    my $i = 0;    for(1..$n) {	$i = index($$buf_ref,$str,$i+1);	if($i == -1) { last }    }    return $i;}{    my @robin_queue;    sub round_robin_write {	# Input:	#   $header_ref = ref to $header string	#   $block_ref = ref to $block to be written	#   $recstart = record start string	#   $recend = record end string	#   $endpos = end position of $block	# Uses:	#   %Global::running	my ($header_ref,$block_ref,$recstart,$recend,$endpos) = @_;	my $something_written = 0;	my $block_passed = 0;	my $sleep = 1;	while(not $block_passed) {	    # Continue flushing existing buffers	    # until one is empty and a new block is passed	    # Make a queue to spread the blocks evenly	    if(not @robin_queue) {		push @robin_queue, values %Global::running;	    }	    while(my $job = shift @robin_queue) {		if($job->stdin_buffer_length() > 0) {		    $something_written += $job->non_block_write();		} else {		    $job->set_stdin_buffer($header_ref,$block_ref,$endpos,$recstart,$recend);		    $block_passed = 1;		    $job->set_virgin(0);		    $something_written += $job->non_block_write();		    last;		}	    }	    $sleep = ::reap_usleep($sleep);	}	return $something_written;    }}sub write_record_to_pipe {    # Fork then    # Write record from pos 0 .. $endpos to pipe    # Input:    #   $chunk_number = sequence number - to see if already run    #   $header_ref = reference to header string to prepend    #   $record_ref = reference to record to write    #   $recstart = start string of record    #   $recend = end string of record    #   $endpos = position in $record_ref where record ends    # Uses:    #   $Global::job_already_run    #   $opt::roundrobin    #   @Global::virgin_jobs    # Returns:    #   Number of chunks written (0 or 1)    my ($chunk_number,$header_ref,$record_ref,$recstart,$recend,$endpos) = @_;    if($endpos == 0) { return 0; }    if(vec($Global::job_already_run,$chunk_number,1)) { return 1; }    if($opt::roundrobin) {	return round_robin_write($header_ref,$record_ref,$recstart,$recend,$endpos);    }    # If no virgin found, backoff    my $sleep = 0.0001; # 0.01 ms - better performance on highend    while(not @Global::virgin_jobs) {	::debug("pipe", "No virgin jobs");	$sleep = ::reap_usleep($sleep);	# Jobs may not be started because of loadavg	# or too little time between each ssh login.	start_more_jobs();    }    my $job = shift @Global::virgin_jobs;    # Job is no longer virgin    $job->set_virgin(0);    if(fork()) {	# Skip    } else {	# Chop of at $endpos as we do not know how many rec_sep will	# be removed.	substr($$record_ref,$endpos,length $$record_ref) = "";	# Remove rec_sep	if($opt::remove_rec_sep) {	    Job::remove_rec_sep($record_ref,$recstart,$recend);	}	$job->write($header_ref);	$job->write($record_ref);	close $job->fh(0,"w");	exit(0);    }    close $job->fh(0,"w");    return 1;}sub __SEM_MODE__ {}sub acquire_semaphore {    # Acquires semaphore. If needed: spawns to the background    # Uses:    #   @Global::host    # Returns:    #   The semaphore to be released when jobs is complete    $Global::host{':'} = SSHLogin->new(":");    my $sem = Semaphore->new($Semaphore::name,$Global::host{':'}->max_jobs_running());    $sem->acquire();    if($Semaphore::fg) {	# skip    } else {	# If run in the background, the PID will change	# therefore release and re-acquire the semaphore	$sem->release();	if(fork()) {	    exit(0);	} else {	    # child	    # Get a semaphore for this pid	    ::die_bug("Can't start a new session: $!") if setsid() == -1;	    $sem = Semaphore->new($Semaphore::name,$Global::host{':'}->max_jobs_running());	    $sem->acquire();	}    }    return $sem;}sub __PARSE_OPTIONS__ {}sub options_hash {    # Returns:    #   %hash = the GetOptions config    return	("debug|D=s" => \$opt::D,	 "xargs" => \$opt::xargs,	 "m" => \$opt::m,	 "X" => \$opt::X,	 "v" => \@opt::v,	 "joblog=s" => \$opt::joblog,	 "results|result|res=s" => \$opt::results,	 "resume" => \$opt::resume,	 "resume-failed|resumefailed" => \$opt::resume_failed,	 "silent" => \$opt::silent,	 #"silent-error|silenterror" => \$opt::silent_error,	 "keep-order|keeporder|k" => \$opt::keeporder,	 "group" => \$opt::group,	 "g" => \$opt::retired,	 "ungroup|u" => \$opt::ungroup,	 "linebuffer|linebuffered|line-buffer|line-buffered" => \$opt::linebuffer,	 "tmux" => \$opt::tmux,	 "null|0" => \$opt::0,	 "quote|q" => \$opt::q,	 # Replacement strings	 "parens=s" => \$opt::parens,	 "rpl=s" => \@opt::rpl,	 "plus" => \$opt::plus,	 "I=s" => \$opt::I,	 "extensionreplace|er=s" => \$opt::U,	 "U=s" => \$opt::retired,	 "basenamereplace|bnr=s" => \$opt::basenamereplace,	 "dirnamereplace|dnr=s" => \$opt::dirnamereplace,	 "basenameextensionreplace|bner=s" => \$opt::basenameextensionreplace,	 "seqreplace=s" => \$opt::seqreplace,	 "slotreplace=s" => \$opt::slotreplace,	 "jobs|j=s" => \$opt::jobs,	 "delay=f" => \$opt::delay,	 "sshdelay=f" => \$opt::sshdelay,	 "load=s" => \$opt::load,	 "noswap" => \$opt::noswap,	 "max-line-length-allowed" => \$opt::max_line_length_allowed,	 "number-of-cpus" => \$opt::number_of_cpus,	 "number-of-cores" => \$opt::number_of_cores,	 "use-cpus-instead-of-cores" => \$opt::use_cpus_instead_of_cores,	 "shellquote|shell_quote|shell-quote" => \$opt::shellquote,	 "nice=i" => \$opt::nice,	 "timeout=s" => \$opt::timeout,	 "tag" => \$opt::tag,	 "tagstring|tag-string=s" => \$opt::tagstring,	 "onall" => \$opt::onall,	 "nonall" => \$opt::nonall,	 "filter-hosts|filterhosts|filter-host" => \$opt::filter_hosts,	 "sshlogin|S=s" => \@opt::sshlogin,	 "sshloginfile|slf=s" => \@opt::sshloginfile,	 "controlmaster|M" => \$opt::controlmaster,	 "return=s" => \@opt::return,	 "trc=s" => \@opt::trc,	 "transfer" => \$opt::transfer,	 "cleanup" => \$opt::cleanup,	 "basefile|bf=s" => \@opt::basefile,	 "B=s" => \$opt::retired,	 "ctrlc|ctrl-c" => \$opt::ctrlc,	 "noctrlc|no-ctrlc|no-ctrl-c" => \$opt::noctrlc,	 "workdir|work-dir|wd=s" => \$opt::workdir,	 "W=s" => \$opt::retired,	 "tmpdir=s" => \$opt::tmpdir,	 "tempdir=s" => \$opt::tmpdir,	 "use-compress-program|compress-program=s" => \$opt::compress_program,	 "use-decompress-program|decompress-program=s" => \$opt::decompress_program,	 "compress" => \$opt::compress,	 "tty" => \$opt::tty,	 "T" => \$opt::retired,	 "halt-on-error|halt=s" => \$opt::halt_on_error,	 "H=i" => \$opt::retired,	 "retries=i" => \$opt::retries,	 "dry-run|dryrun" => \$opt::dryrun,	 "progress" => \$opt::progress,	 "eta" => \$opt::eta,	 "bar" => \$opt::bar,	 "arg-sep|argsep=s" => \$opt::arg_sep,	 "arg-file-sep|argfilesep=s" => \$opt::arg_file_sep,	 "trim=s" => \$opt::trim,	 "env=s" => \@opt::env,	 "recordenv|record-env" => \$opt::record_env,	 "plain" => \$opt::plain,	 "profile|J=s" => \@opt::profile,	 "pipe|spreadstdin" => \$opt::pipe,	 "robin|round-robin|roundrobin" => \$opt::roundrobin,	 "recstart=s" => \$opt::recstart,	 "recend=s" => \$opt::recend,	 "regexp|regex" => \$opt::regexp,	 "remove-rec-sep|removerecsep|rrs" => \$opt::remove_rec_sep,	 "files|output-as-files|outputasfiles" => \$opt::files,	 "block|block-size|blocksize=s" => \$opt::blocksize,	 "tollef" => \$opt::retired,	 "gnu" => \$opt::gnu,	 "xapply" => \$opt::xapply,	 "bibtex" => \$opt::bibtex,	 "nn|nonotice|no-notice" => \$opt::no_notice,	 # xargs-compatibility - implemented, man, testsuite	 "max-procs|P=s" => \$opt::jobs,	 "delimiter|d=s" => \$opt::d,	 "max-chars|s=i" => \$opt::max_chars,	 "arg-file|a=s" => \@opt::a,	 "no-run-if-empty|r" => \$opt::r,	 "replace|i:s" => \$opt::i,	 "E=s" => \$opt::eof,	 "eof|e:s" => \$opt::eof,	 "max-args|n=i" => \$opt::max_args,	 "max-replace-args|N=i" => \$opt::max_replace_args,	 "colsep|col-sep|C=s" => \$opt::colsep,	 "help|h" => \$opt::help,	 "L=f" => \$opt::L,	 "max-lines|l:f" => \$opt::max_lines,	 "interactive|p" => \$opt::p,	 "verbose|t" => \$opt::verbose,	 "version|V" => \$opt::version,	 "minversion|min-version=i" => \$opt::minversion,	 "show-limits|showlimits" => \$opt::show_limits,	 "exit|x" => \$opt::x,	 # Semaphore	 "semaphore" => \$opt::semaphore,	 "semaphoretimeout=i" => \$opt::semaphoretimeout,	 "semaphorename|id=s" => \$opt::semaphorename,	 "fg" => \$opt::fg,	 "bg" => \$opt::bg,	 "wait" => \$opt::wait,	 # Shebang #!/usr/bin/parallel --shebang	 "shebang|hashbang" => \$opt::shebang,	 "internal-pipe-means-argfiles" => \$opt::internal_pipe_means_argfiles,	 "Y" => \$opt::retired,         "skip-first-line" => \$opt::skip_first_line,	 "header=s" => \$opt::header,	 "cat" => \$opt::cat,	 "fifo" => \$opt::fifo,	 "pipepart|pipe-part" => \$opt::pipepart,	 "hgrp|hostgroup|hostgroups" => \$opt::hostgroups,	);}sub get_options_from_array {    # Run GetOptions on @array    # Input:    #   $array_ref = ref to @ARGV to parse    #   @keep_only = Keep only these options    # Uses:    #   @ARGV    # Returns:    #   true if parsing worked    #   false if parsing failed    #   @$array_ref is changed    my ($array_ref, @keep_only) = @_;    if(not @$array_ref) {	# Empty array: No need to look more at that	return 1;    }    # A bit of shuffling of @ARGV needed as GetOptionsFromArray is not    # supported everywhere    my @save_argv;    my $this_is_ARGV = (\@::ARGV == $array_ref);    if(not $this_is_ARGV) {	@save_argv = @::ARGV;	@::ARGV = @{$array_ref};    }    # If @keep_only set: Ignore all values except @keep_only    my %options = options_hash();    if(@keep_only) {	my (%keep,@dummy);	@keep{@keep_only} = @keep_only;	for my $k (grep { not $keep{$_} } keys %options) {	    # Store the value of the option in @dummy	    $options{$k} = \@dummy;	}    }    my $retval = GetOptions(%options);    if(not $this_is_ARGV) {	@{$array_ref} = @::ARGV;	@::ARGV = @save_argv;    }    return $retval;}sub parse_options {    # Returns: N/A    # Defaults:    $Global::version = 20141122;    $Global::progname = 'parallel';    $Global::infinity = 2**31;    $Global::debug = 0;    $Global::verbose = 0;    $Global::quoting = 0;    # Read only table with default --rpl values    %Global::replace =	(	 '{}'   => '',	 '{#}'  => '1 $_=$job->seq()',	 '{%}'  => '1 $_=$job->slot()',	 '{/}'  => 's:.*/::',	 '{//}' => '$Global::use{"File::Basename"} ||= eval "use File::Basename; 1;"; $_ = dirname($_);',	 '{/.}' => 's:.*/::; s:\.[^/.]+$::;',	 '{.}'  => 's:\.[^/.]+$::',	);    %Global::plus =	(	 # {} = {+/}/{/}	 #    = {.}.{+.}     = {+/}/{/.}.{+.}	 #    = {..}.{+..}   = {+/}/{/..}.{+..}	 #    = {...}.{+...} = {+/}/{/...}.{+...}	 '{+/}' => 's:/[^/]*$::',	 '{+.}' => 's:.*\.::',	 '{+..}' => 's:.*\.([^.]*\.):$1:',	 '{+...}' => 's:.*\.([^.]*\.[^.]*\.):$1:',	 '{..}' => 's:\.[^/.]+$::; s:\.[^/.]+$::',	 '{...}' => 's:\.[^/.]+$::; s:\.[^/.]+$::; s:\.[^/.]+$::',	 '{/..}' => 's:.*/::; s:\.[^/.]+$::; s:\.[^/.]+$::',	 '{/...}' => 's:.*/::; s:\.[^/.]+$::; s:\.[^/.]+$::; s:\.[^/.]+$::',	);    # Modifiable copy of %Global::replace    %Global::rpl = %Global::replace;    $Global::parens = "{==}";    $/="\n";    $Global::ignore_empty = 0;    $Global::interactive = 0;    $Global::stderr_verbose = 0;    $Global::default_simultaneous_sshlogins = 9;    $Global::exitstatus = 0;    $Global::halt_on_error_exitstatus = 0;    $Global::arg_sep = ":::";    $Global::arg_file_sep = "::::";    $Global::trim = 'n';    $Global::max_jobs_running = 0;    $Global::job_already_run = '';    $ENV{'TMPDIR'} ||= "/tmp";    @ARGV=read_options();    if(@opt::v) { $Global::verbose = $#opt::v+1; } # Convert -v -v to v=2    $Global::debug = $opt::D;    $Global::shell = $ENV{'PARALLEL_SHELL'} || parent_shell($$) || $ENV{'SHELL'} || "/bin/sh";    if(defined $opt::X) { $Global::ContextReplace = 1; }    if(defined $opt::silent) { $Global::verbose = 0; }    if(defined $opt::0) { $/ = "\0"; }    if(defined $opt::d) { my $e="sprintf \"$opt::d\""; $/ = eval $e; }    if(defined $opt::p) { $Global::interactive = $opt::p; }    if(defined $opt::q) { $Global::quoting = 1; }    if(defined $opt::r) { $Global::ignore_empty = 1; }    if(defined $opt::verbose) { $Global::stderr_verbose = 1; }    # Deal with --rpl    sub rpl {	# Modify %Global::rpl	# Replace $old with $new	my ($old,$new) =  @_;	if($old ne $new) {	    $Global::rpl{$new} = $Global::rpl{$old};	    delete $Global::rpl{$old};	}    }    if(defined $opt::parens) { $Global::parens = $opt::parens; }    my $parenslen = 0.5*length $Global::parens;    $Global::parensleft = substr($Global::parens,0,$parenslen);    $Global::parensright = substr($Global::parens,$parenslen);    if(defined $opt::plus) { %Global::rpl = (%Global::plus,%Global::rpl); }    if(defined $opt::I) { rpl('{}',$opt::I); }    if(defined $opt::U) { rpl('{.}',$opt::U); }    if(defined $opt::i and $opt::i) { rpl('{}',$opt::i); }    if(defined $opt::basenamereplace) { rpl('{/}',$opt::basenamereplace); }    if(defined $opt::dirnamereplace) { rpl('{//}',$opt::dirnamereplace); }    if(defined $opt::seqreplace) { rpl('{#}',$opt::seqreplace); }    if(defined $opt::slotreplace) { rpl('{%}',$opt::slotreplace); }    if(defined $opt::basenameextensionreplace) {       rpl('{/.}',$opt::basenameextensionreplace);    }    for(@opt::rpl) {	# Create $Global::rpl entries for --rpl options	# E.g: "{..} s:\.[^.]+$:;s:\.[^.]+$:;"	my ($shorthand,$long) = split/ /,$_,2;	$Global::rpl{$shorthand} = $long;    }    if(defined $opt::eof) { $Global::end_of_file_string = $opt::eof; }    if(defined $opt::max_args) { $Global::max_number_of_args = $opt::max_args; }    if(defined $opt::timeout) { $Global::timeoutq = TimeoutQueue->new($opt::timeout); }    if(defined $opt::tmpdir) { $ENV{'TMPDIR'} = $opt::tmpdir; }    if(defined $opt::help) { die_usage(); }    if(defined $opt::colsep) { $Global::trim = 'lr'; }    if(defined $opt::header) { $opt::colsep = defined $opt::colsep ? $opt::colsep : "\t"; }    if(defined $opt::trim) { $Global::trim = $opt::trim; }    if(defined $opt::arg_sep) { $Global::arg_sep = $opt::arg_sep; }    if(defined $opt::arg_file_sep) { $Global::arg_file_sep = $opt::arg_file_sep; }    if(defined $opt::number_of_cpus) { print SSHLogin::no_of_cpus(),"\n"; wait_and_exit(0); }    if(defined $opt::number_of_cores) {        print SSHLogin::no_of_cores(),"\n"; wait_and_exit(0);    }    if(defined $opt::max_line_length_allowed) {        print Limits::Command::real_max_length(),"\n"; wait_and_exit(0);    }    if(defined $opt::version) { version(); wait_and_exit(0); }    if(defined $opt::bibtex) { bibtex(); wait_and_exit(0); }    if(defined $opt::record_env) { record_env(); wait_and_exit(0); }    if(defined $opt::show_limits) { show_limits(); }    if(@opt::sshlogin) { @Global::sshlogin = @opt::sshlogin; }    if(@opt::sshloginfile) { read_sshloginfiles(@opt::sshloginfile); }    if(@opt::return) { push @Global::ret_files, @opt::return; }    if(not defined $opt::recstart and       not defined $opt::recend) { $opt::recend = "\n"; }    if(not defined $opt::blocksize) { $opt::blocksize = "1M"; }    $opt::blocksize = multiply_binary_prefix($opt::blocksize);    if(defined $opt::controlmaster) { $opt::noctrlc = 1; }    if(defined $opt::semaphore) { $Global::semaphore = 1; }    if(defined $opt::semaphoretimeout) { $Global::semaphore = 1; }    if(defined $opt::semaphorename) { $Global::semaphore = 1; }    if(defined $opt::fg) { $Global::semaphore = 1; }    if(defined $opt::bg) { $Global::semaphore = 1; }    if(defined $opt::wait) { $Global::semaphore = 1; }    if(defined $opt::halt_on_error and       $opt::halt_on_error=~/%/) { $opt::halt_on_error /= 100; }    if(defined $opt::timeout and $opt::timeout !~ /^\d+(\.\d+)?%?$/) {	::error("--timeout must be seconds or percentage\n");	wait_and_exit(255);    }    if(defined $opt::minversion) {	print $Global::version,"\n";	if($Global::version < $opt::minversion) {	    wait_and_exit(255);	} else {	    wait_and_exit(0);	}    }    if(not defined $opt::delay) {	# Set --delay to --sshdelay if not set	$opt::delay = $opt::sshdelay;    }    if($opt::compress_program) {	$opt::compress = 1;	$opt::decompress_program ||= $opt::compress_program." -dc";    }    if($opt::compress) {	my ($compress, $decompress) = find_compression_program();	$opt::compress_program ||= $compress;	$opt::decompress_program ||= $decompress;    }    if(defined $opt::nonall) {	# Append a dummy empty argument	push @ARGV, $Global::arg_sep, "";    }    if(defined $opt::tty) {        # Defaults for --tty: -j1 -u        # Can be overridden with -jXXX -g        if(not defined $opt::jobs) {            $opt::jobs = 1;        }        if(not defined $opt::group) {            $opt::ungroup = 0;        }    }    if(@opt::trc) {        push @Global::ret_files, @opt::trc;        $opt::transfer = 1;        $opt::cleanup = 1;    }    if(defined $opt::max_lines) {	if($opt::max_lines eq "-0") {	    # -l -0 (swallowed -0)	    $opt::max_lines = 1;	    $opt::0 = 1;	    $/ = "\0";	} elsif ($opt::max_lines == 0) {	    # If not given (or if 0 is given) => 1	    $opt::max_lines = 1;	}	$Global::max_lines = $opt::max_lines;	if(not $opt::pipe) {	    # --pipe -L means length of record - not max_number_of_args	    $Global::max_number_of_args ||= $Global::max_lines;	}    }    # Read more than one arg at a time (-L, -N)    if(defined $opt::L) {	$Global::max_lines = $opt::L;	if(not $opt::pipe) {	    # --pipe -L means length of record - not max_number_of_args	    $Global::max_number_of_args ||= $Global::max_lines;	}    }    if(defined $opt::max_replace_args) {	$Global::max_number_of_args = $opt::max_replace_args;	$Global::ContextReplace = 1;    }    if((defined $opt::L or defined $opt::max_replace_args)       and       not ($opt::xargs or $opt::m)) {	$Global::ContextReplace = 1;    }    if(defined $opt::tag and not defined $opt::tagstring) {	$opt::tagstring = "\257<\257>"; # Default = {}    }    if(defined $opt::pipepart and       (defined $opt::L or defined $opt::max_lines	or defined $opt::max_replace_args)) {	::error("--pipepart is incompatible with --max-replace-args, ",		"--max-lines, and -L.\n");	wait_and_exit(255);    }    if(grep /^$Global::arg_sep$|^$Global::arg_file_sep$/o, @ARGV) {        # Deal with ::: and ::::        @ARGV=read_args_from_command_line();    }    # Semaphore defaults    # Must be done before computing number of processes and max_line_length    # because when running as a semaphore GNU Parallel does not read args    $Global::semaphore ||= ($0 =~ m:(^|/)sem$:); # called as 'sem'    if($Global::semaphore) {        # A semaphore does not take input from neither stdin nor file        @opt::a = ("/dev/null");        push(@Global::unget_argv, [Arg->new("")]);        $Semaphore::timeout = $opt::semaphoretimeout || 0;        if(defined $opt::semaphorename) {            $Semaphore::name = $opt::semaphorename;        } else {            $Semaphore::name = `tty`;            chomp $Semaphore::name;        }        $Semaphore::fg = $opt::fg;        $Semaphore::wait = $opt::wait;        $Global::default_simultaneous_sshlogins = 1;        if(not defined $opt::jobs) {            $opt::jobs = 1;        }	if($Global::interactive and $opt::bg) {	    ::error("Jobs running in the ".		    "background cannot be interactive.\n");            ::wait_and_exit(255);	}    }    if(defined $opt::eta) {        $opt::progress = $opt::eta;    }    if(defined $opt::bar) {        $opt::progress = $opt::bar;    }    if(defined $opt::retired) {	    ::error("-g has been retired. Use --group.\n");	    ::error("-B has been retired. Use --bf.\n");	    ::error("-T has been retired. Use --tty.\n");	    ::error("-U has been retired. Use --er.\n");	    ::error("-W has been retired. Use --wd.\n");	    ::error("-Y has been retired. Use --shebang.\n");	    ::error("-H has been retired. Use --halt.\n");	    ::error("--tollef has been retired. Use -u -q --arg-sep -- and --load for -l.\n");            ::wait_and_exit(255);    }    citation_notice();    parse_sshlogin();    parse_env_var();    if(remote_hosts() and ($opt::X or $opt::m or $opt::xargs)) {        # As we do not know the max line length on the remote machine        # long commands generated by xargs may fail        # If opt_N is set, it is probably safe        ::warning("Using -X or -m with --sshlogin may fail.\n");    }    if(not defined $opt::jobs) {        $opt::jobs = "100%";    }    open_joblog();}sub env_quote {    # Input:    #   $v = value to quote    # Returns:    #   $v = value quoted as environment variable    my $v = $_[0];    $v =~ s/([\\])/\\$1/g;    $v =~ s/([\[\] \#\'\&\<\>\(\)\;\{\}\t\"\$\`\*\174\!\?\~])/\\$1/g;    $v =~ s/\n/"\n"/g;    return $v;}sub record_env {    # Record current %ENV-keys in ~/.parallel/ignored_vars    # Returns: N/A    my $ignore_filename = $ENV{'HOME'} . "/.parallel/ignored_vars";    if(open(my $vars_fh, ">", $ignore_filename)) {	print $vars_fh map { $_,"\n" } keys %ENV;    } else {	::error("Cannot write to $ignore_filename\n");	::wait_and_exit(255);    }}sub parse_env_var {    # Parse --env and set $Global::envvar, $Global::envwarn and $Global::envvarlen    #    # Bash functions must be parsed to export them remotely    #   Pre-shellshock style bash function:    #     myfunc=() {...    #   Post-shellshock style bash function:    #     BASH_FUNC_myfunc()=() {...    #    # Uses:    #   $Global::envvar = eval string that will set variables in both bash and csh    #   $Global::envwarn = If functions are used: Give warning in csh    #   $Global::envvarlen = length of $Global::envvar    #   @opt::env    #   $Global::shell    #   %ENV    # Returns: N/A    $Global::envvar = "";    $Global::envwarn = "";    my @vars = ('parallel_bash_environment');    for my $varstring (@opt::env) {        # Split up --env VAR1,VAR2	push @vars, split /,/, $varstring;    }    if(grep { /^_$/ } @vars) {	# --env _	# Include all vars that are not in a clean environment	if(open(my $vars_fh, "<", $ENV{'HOME'} . "/.parallel/ignored_vars")) {	    my @ignore = <$vars_fh>;	    chomp @ignore;	    my %ignore;	    @ignore{@ignore} = @ignore;	    close $vars_fh;	    push @vars, grep { not defined $ignore{$_} } keys %ENV;	    @vars = grep { not /^_$/ } @vars;	} else {	    ::error("Run '$Global::progname --record-env' in a clean environment first.\n");	    ::wait_and_exit(255);	}    }    # Duplicate vars as BASH functions to include post-shellshock functions.    # So --env myfunc should also look for BASH_FUNC_myfunc()    @vars = map { $_, "BASH_FUNC_$_()" } @vars;    # Keep only defined variables    @vars = grep { defined($ENV{$_}) } @vars;    # Pre-shellshock style bash function:    #   myfunc=() {  echo myfunc    #   }    # Post-shellshock style bash function:    #   BASH_FUNC_myfunc()=() {  echo myfunc    #   }    my @bash_functions = grep { substr($ENV{$_},0,4) eq "() {" } @vars;    my @non_functions = grep { substr($ENV{$_},0,4) ne "() {" } @vars;    if(@bash_functions) {	# Functions are not supported for all shells	if($Global::shell !~ m:/(bash|rbash|zsh|rzsh|dash|ksh):) {	    ::warning("Shell functions may not be supported in $Global::shell\n");	}    }    # Pre-shellschock names are without ()    my @bash_pre_shellshock = grep { not /\(\)/ } @bash_functions;    # Post-shellschock names are with ()    my @bash_post_shellshock = grep { /\(\)/ } @bash_functions;    my @qcsh = (map { my $a=$_; "setenv $a " . env_quote($ENV{$a})  }		grep { not /^parallel_bash_environment$/ } @non_functions);    my @qbash = (map { my $a=$_; "export $a=" . env_quote($ENV{$a}) }		 @non_functions, @bash_pre_shellshock);    push @qbash, map { my $a=$_; "eval $a\"\$$a\"" } @bash_pre_shellshock;    push @qbash, map { /BASH_FUNC_(.*)\(\)/; "$1 $ENV{$_}" } @bash_post_shellshock;    #ssh -tt -oLogLevel=quiet lo 'eval `echo PARALLEL_SEQ='$PARALLEL_SEQ'\;export PARALLEL_SEQ\;  PARALLEL_PID='$PARALLEL_PID'\;export PARALLEL_PID` ;'  tty\ \>/dev/null\ \&\&\ stty\ isig\ -onlcr\ -echo\;echo\ \$SHELL\ \|\ grep\ \"/t\\\{0,1\\\}csh\"\ \>\ /dev/null\ \&\&\ setenv\ BASH_FUNC_myfunc\ \\\(\\\)\\\ \\\{\\\ \\\ echo\\\ a\"'    #'\"\\\}\ \|\|\  myfunc\(\)\ \{\ \ echo\ a'    #'\}\ \;myfunc\ 1;    # Check if any variables contain \n    if(my @v = map { s/BASH_FUNC_(.*)\(\)/$1/; $_ } grep { $ENV{$_}=~/\n/ } @vars) {	# \n is bad for csh and will cause it to fail.	$Global::envwarn = ::shell_quote_scalar(q{echo $SHELL | egrep "/t?csh" > /dev/null && echo CSH/TCSH DO NOT SUPPORT newlines IN VARIABLES/FUNCTIONS. Unset }."@v".q{ && exec false;}."\n\n") . $Global::envwarn;    }    if(not @qcsh) { push @qcsh, "true"; }    if(not @qbash) { push @qbash, "true"; }    # Create lines like:    # echo $SHELL | grep "/t\\{0,1\\}csh" >/dev/null && setenv V1 val1 && setenv V2 val2 || export V1=val1 && export V2=val2 ; echo "$V1$V2"    if(@vars) {	$Global::envvar .=	    join"",	    (q{echo $SHELL | grep "/t\\{0,1\\}csh" > /dev/null && }	     . join(" && ", @qcsh)	     . q{ || }	     . join(" && ", @qbash)	     .q{;});	if($ENV{'parallel_bash_environment'}) {	    $Global::envvar .= 'eval "$parallel_bash_environment";'."\n";	}    }    $Global::envvarlen = length $Global::envvar;}sub open_joblog {    # Open joblog as specified by --joblog    # Uses:    #   $opt::resume    #   $opt::resume_failed    #   $opt::joblog    #   $opt::results    #   $Global::job_already_run    #   %Global::fd    my $append = 0;    if(($opt::resume or $opt::resume_failed)       and       not ($opt::joblog or $opt::results)) {        ::error("--resume and --resume-failed require --joblog or --results.\n");	::wait_and_exit(255);    }    if($opt::joblog) {	if($opt::resume || $opt::resume_failed) {	    if(open(my $joblog_fh, "<", $opt::joblog)) {		# Read the joblog		$append = <$joblog_fh>; # If there is a header: Open as append later		my $joblog_regexp;		if($opt::resume_failed) {		    # Make a regexp that only matches commands with exit+signal=0		    # 4 host 1360490623.067 3.445 1023 1222 0 0 command		    $joblog_regexp='^(\d+)(?:\t[^\t]+){5}\t0\t0\t';		} else {		    # Just match the job number		    $joblog_regexp='^(\d+)';		}		while(<$joblog_fh>) {		    if(/$joblog_regexp/o) {			# This is 30% faster than set_job_already_run($1);			vec($Global::job_already_run,($1||0),1) = 1;		    } elsif(not /\d+\s+[^\s]+\s+([0-9.]+\s+){6}/) {			::error("Format of '$opt::joblog' is wrong: $_");			::wait_and_exit(255);		    }		}		close $joblog_fh;	    }	}	if($append) {	    # Append to joblog	    if(not open($Global::joblog, ">>", $opt::joblog)) {		::error("Cannot append to --joblog $opt::joblog.\n");		::wait_and_exit(255);	    }	} else {	    if($opt::joblog eq "-") {		# Use STDOUT as joblog		$Global::joblog = $Global::fd{1};	    } elsif(not open($Global::joblog, ">", $opt::joblog)) {		# Overwrite the joblog		::error("Cannot write to --joblog $opt::joblog.\n");		::wait_and_exit(255);	    }	    print $Global::joblog		join("\t", "Seq", "Host", "Starttime", "JobRuntime",		     "Send", "Receive", "Exitval", "Signal", "Command"		). "\n";	}    }}sub find_compression_program {    # Find a fast compression program    # Returns:    #   $compress_program = compress program with options    #   $decompress_program = decompress program with options    # Search for these. Sorted by speed    my @prg = qw(lzop pigz pxz gzip plzip pbzip2 lzma xz lzip bzip2);    for my $p (@prg) {	if(which($p)) {	    return ("$p -c -1","$p -dc");	}    }    # Fall back to cat    return ("cat","cat");}sub read_options {    # Read options from command line, profile and $PARALLEL    # Uses:    #   $opt::shebang_wrap    #   $opt::shebang    #   @ARGV    #   $opt::plain    #   @opt::profile    #   $ENV{'HOME'}    #   $ENV{'PARALLEL'}    # Returns:    #   @ARGV_no_opt = @ARGV without --options    # This must be done first as this may exec myself    if(defined $ARGV[0] and ($ARGV[0] =~ /^--shebang/ or			     $ARGV[0] =~ /^--shebang-?wrap/ or			     $ARGV[0] =~ /^--hashbang/)) {        # Program is called from #! line in script	# remove --shebang-wrap if it is set        $opt::shebang_wrap = ($ARGV[0] =~ s/^--shebang-?wrap *//);	# remove --shebang if it is set	$opt::shebang = ($ARGV[0] =~ s/^--shebang *//);	# remove --hashbang if it is set        $opt::shebang .= ($ARGV[0] =~ s/^--hashbang *//);	if($opt::shebang) {	    my $argfile = shell_quote_scalar(pop @ARGV);	    # exec myself to split $ARGV[0] into separate fields	    exec "$0 --skip-first-line -a $argfile @ARGV";	}	if($opt::shebang_wrap) {            my @options;	    my @parser;	    if ($^O eq 'freebsd') {		# FreeBSD's #! puts different values in @ARGV than Linux' does.		my @nooptions = @ARGV;		get_options_from_array(\@nooptions);		while($#ARGV > $#nooptions) {		    push @options, shift @ARGV;		}		while(@ARGV and $ARGV[0] ne ":::") {		    push @parser, shift @ARGV;		}		if(@ARGV and $ARGV[0] eq ":::") {		    shift @ARGV;		}	    } else {		@options = shift @ARGV;	    }	    my $script = shell_quote_scalar(shift @ARGV);	    # exec myself to split $ARGV[0] into separate fields	    exec "$0 --internal-pipe-means-argfiles @options @parser $script ::: @ARGV";	}    }    Getopt::Long::Configure("bundling","require_order");    my @ARGV_copy = @ARGV;    # Check if there is a --profile to set @opt::profile    get_options_from_array(\@ARGV_copy,"profile|J=s","plain") || die_usage();    my @ARGV_profile = ();    my @ARGV_env = ();    if(not $opt::plain) {	# Add options from .parallel/config and other profiles	my @config_profiles = (	    "/etc/parallel/config",	    $ENV{'HOME'}."/.parallel/config",	    $ENV{'HOME'}."/.parallelrc");	my @profiles = @config_profiles;	if(@opt::profile) {	    # --profile overrides default profiles	    @profiles = ();	    for my $profile (@opt::profile) {		if(-r $profile) {		    push @profiles, $profile;		} else {		    push @profiles, $ENV{'HOME'}."/.parallel/".$profile;		}	    }	}	for my $profile (@profiles) {	    if(-r $profile) {		open (my $in_fh, "<", $profile) || ::die_bug("read-profile: $profile");		while(<$in_fh>) {		    /^\s*\#/ and next;		    chomp;		    push @ARGV_profile, shellwords($_);		}		close $in_fh;	    } else {		if(grep /^$profile$/, @config_profiles) {		    # config file is not required to exist		} else {		    ::error("$profile not readable.\n");		    wait_and_exit(255);		}	    }	}	# Add options from shell variable $PARALLEL	if($ENV{'PARALLEL'}) {	    @ARGV_env = shellwords($ENV{'PARALLEL'});	}    }    Getopt::Long::Configure("bundling","require_order");    get_options_from_array(\@ARGV_profile) || die_usage();    get_options_from_array(\@ARGV_env) || die_usage();    get_options_from_array(\@ARGV) || die_usage();    # Prepend non-options to @ARGV (such as commands like 'nice')    unshift @ARGV, @ARGV_profile, @ARGV_env;    return @ARGV;}sub read_args_from_command_line {    # Arguments given on the command line after:    #   ::: ($Global::arg_sep)    #   :::: ($Global::arg_file_sep)    # Removes the arguments from @ARGV and:    # - puts filenames into -a    # - puts arguments into files and add the files to -a    # Input:    #   @::ARGV = command option ::: arg arg arg :::: argfiles    # Uses:    #   $Global::arg_sep    #   $Global::arg_file_sep    #   $opt::internal_pipe_means_argfiles    #   $opt::pipe    #   @opt::a    # Returns:    #   @argv_no_argsep = @::ARGV without ::: and :::: and following args    my @new_argv = ();    for(my $arg = shift @ARGV; @ARGV; $arg = shift @ARGV) {        if($arg eq $Global::arg_sep	   or	   $arg eq $Global::arg_file_sep) {	    my $group = $arg; # This group of arguments is args or argfiles	    my @group;	    while(defined ($arg = shift @ARGV)) {		if($arg eq $Global::arg_sep		   or		   $arg eq $Global::arg_file_sep) {		    # exit while loop if finding new separator		    last;		} else {		    # If not hitting ::: or ::::		    # Append it to the group		    push @group, $arg;		}	    }	    if($group eq $Global::arg_file_sep	       or ($opt::internal_pipe_means_argfiles and $opt::pipe)		) {		# Group of file names on the command line.		# Append args into -a		push @opt::a, @group;	    } elsif($group eq $Global::arg_sep) {		# Group of arguments on the command line.		# Put them into a file.		# Create argfile		my ($outfh,$name) = ::tmpfile(SUFFIX => ".arg");		unlink($name);		# Put args into argfile		print $outfh map { $_,$/ } @group;		seek $outfh, 0, 0;		# Append filehandle to -a		push @opt::a, $outfh;	    } else {		::die_bug("Unknown command line group: $group");	    }	    if(defined($arg)) {		# $arg is ::: or ::::		redo;	    } else {		# $arg is undef -> @ARGV empty		last;	    }	}	push @new_argv, $arg;    }    # Output: @ARGV = command to run with options    return @new_argv;}sub cleanup {    # Returns: N/A    if(@opt::basefile) { cleanup_basefile(); }}sub __QUOTING_ARGUMENTS_FOR_SHELL__ {}sub shell_quote {    # Input:    #   @strings = strings to be quoted    # Output:    #   @shell_quoted_strings = string quoted with \ as needed by the shell    my @strings = (@_);    for my $a (@strings) {        $a =~ s/([\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\*\>\<\~\|\; \"\!\$\&\'\202-\377])/\\$1/g;        $a =~ s/[\n]/'\n'/g; # filenames with '\n' is quoted using \'    }    return wantarray ? @strings : "@strings";}sub shell_quote_empty {    # Inputs:    #   @strings = strings to be quoted    # Returns:    #   @quoted_strings = empty strings quoted as ''.    my @strings = shell_quote(@_);    for my $a (@strings) {	if($a eq "") {	    $a = "''";	}    }    return wantarray ? @strings : "@strings";}sub shell_quote_scalar {    # Quote the string so shell will not expand any special chars    # Inputs:    #   $string = string to be quoted    # Returns:    #   $shell_quoted = string quoted with \ as needed by the shell    my $a = $_[0];    if(defined $a) {	# $a =~ s/([\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\*\>\<\~\|\; \"\!\$\&\'\202-\377])/\\$1/g;	# This is 1% faster than the above	$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\*\>\<\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;	$a =~ s/[\n]/'\n'/go; # filenames with '\n' is quoted using \'    }    return $a;}sub shell_quote_file {    # Quote the string so shell will not expand any special chars and prepend ./ if needed    # Input:    #   $filename = filename to be shell quoted    # Returns:    #   $quoted_filename = filename quoted with \ as needed by the shell and ./ if needed    my $a = shell_quote_scalar(shift);    if(defined $a) {	if($a =~ m:^/: or $a =~ m:^\./:) {	    # /abs/path or ./rel/path => skip	} else {	    # rel/path => ./rel/path	    $a = "./".$a;	}    }    return $a;}sub shellwords {    # Input:    #   $string = shell line    # Returns:    #   @shell_words = $string split into words as shell would do    $Global::use{"Text::ParseWords"} ||= eval "use Text::ParseWords; 1;";    return Text::ParseWords::shellwords(@_);}sub __FILEHANDLES__ {}sub save_stdin_stdout_stderr {    # Remember the original STDIN, STDOUT and STDERR    # and file descriptors opened by the shell (e.g. 3>/tmp/foo)    # Uses:    #   %Global::fd    #   $Global::original_stderr    #   $Global::original_stdin    # Returns: N/A    # Find file descriptors that are already opened (by the shell)    for my $fdno (1..61) {	# /dev/fd/62 and above are used by bash for <(cmd)	my $fh;	# 2-argument-open is used to be compatible with old perl 5.8.0	# bug #43570: Perl 5.8.0 creates 61 files	if(open($fh,">&=$fdno")) {	    $Global::fd{$fdno}=$fh;	}    }    open $Global::original_stderr, ">&", "STDERR" or	::die_bug("Can't dup STDERR: $!");    open $Global::original_stdin, "<&", "STDIN" or	::die_bug("Can't dup STDIN: $!");}sub enough_file_handles {    # Check that we have enough filehandles available for starting    # another job    # Uses:    #   $opt::ungroup    #   %Global::fd    # Returns:    #   1 if ungrouped (thus not needing extra filehandles)    #   0 if too few filehandles    #   1 if enough filehandles    if(not $opt::ungroup) {        my %fh;        my $enough_filehandles = 1;  	# perl uses 7 filehandles for something?        # open3 uses 2 extra filehandles temporarily        # We need a filehandle for each redirected file descriptor	# (normally just STDOUT and STDERR)	for my $i (1..(7+2+keys %Global::fd)) {            $enough_filehandles &&= open($fh{$i}, "<", "/dev/null");        }        for (values %fh) { close $_; }        return $enough_filehandles;    } else {	# Ungrouped does not need extra file handles	return 1;    }}sub open_or_exit {    # Open a file name or exit if the file cannot be opened    # Inputs:    #   $file = filehandle or filename to open    # Uses:    #   $Global::stdin_in_opt_a    #   $Global::original_stdin    # Returns:    #   $fh = file handle to read-opened file    my $file = shift;    if($file eq "-") {	$Global::stdin_in_opt_a = 1;	return ($Global::original_stdin || *STDIN);    }    if(ref $file eq "GLOB") {	# This is an open filehandle	return $file;    }    my $fh = gensym;    if(not open($fh, "<", $file)) {        ::error("Cannot open input file `$file': No such file or directory.\n");        wait_and_exit(255);    }    return $fh;}sub __RUNNING_THE_JOBS_AND_PRINTING_PROGRESS__ {}# Variable structure:##    $Global::running{$pid} = Pointer to Job-object#    @Global::virgin_jobs = Pointer to Job-object that have received no input#    $Global::host{$sshlogin} = Pointer to SSHLogin-object#    $Global::total_running = total number of running jobs#    $Global::total_started = total jobs startedsub init_run_jobs {    $Global::total_running = 0;    $Global::total_started = 0;    $Global::tty_taken = 0;    $SIG{USR1} = \&list_running_jobs;    $SIG{USR2} = \&toggle_progress;    if(@opt::basefile) { setup_basefile(); }}{    my $last_time;    my %last_mtime;sub start_more_jobs {    # Run start_another_job() but only if:    #   * not $Global::start_no_new_jobs set    #   * not JobQueue is empty    #   * not load on server is too high    #   * not server swapping    #   * not too short time since last remote login    # Uses:    #   $Global::max_procs_file    #   $Global::max_procs_file_last_mod    #   %Global::host    #   @opt::sshloginfile    #   $Global::start_no_new_jobs    #   $opt::filter_hosts    #   $Global::JobQueue    #   $opt::pipe    #   $opt::load    #   $opt::noswap    #   $opt::delay    #   $Global::newest_starttime    # Returns:    #   $jobs_started = number of jobs started    my $jobs_started = 0;    my $jobs_started_this_round = 0;    if($Global::start_no_new_jobs) {	return $jobs_started;    }    if(time - ($last_time||0) > 1) {	# At most do this every second	$last_time = time;	if($Global::max_procs_file) {	    # --jobs filename	    my $mtime = (stat($Global::max_procs_file))[9];	    if($mtime > $Global::max_procs_file_last_mod) {		# file changed: Force re-computing max_jobs_running		$Global::max_procs_file_last_mod = $mtime;		for my $sshlogin (values %Global::host) {		    $sshlogin->set_max_jobs_running(undef);		}	    }	}	if(@opt::sshloginfile) {	    # Is --sshloginfile changed?	    for my $slf (@opt::sshloginfile) {		my $actual_file = expand_slf_shorthand($slf);		my $mtime = (stat($actual_file))[9];		$last_mtime{$actual_file} ||= $mtime;		if($mtime - $last_mtime{$actual_file} > 1) {		    ::debug("run","--sshloginfile $actual_file changed. reload\n");		    $last_mtime{$actual_file} = $mtime;		    # Reload $slf		    # Empty sshlogins		    @Global::sshlogin = ();		    for (values %Global::host) {			# Don't start new jobs on any host			# except the ones added back later			$_->set_max_jobs_running(0);		    }		    # This will set max_jobs_running on the SSHlogins		    read_sshloginfile($actual_file);		    parse_sshlogin();		    $opt::filter_hosts and filter_hosts();		    setup_basefile();		}	    }	}    }    do {	$jobs_started_this_round = 0;	# This will start 1 job on each --sshlogin (if possible)	# thus distribute the jobs on the --sshlogins round robin	for my $sshlogin (values %Global::host) {	    if($Global::JobQueue->empty() and not $opt::pipe) {		# No more jobs in the queue		last;	    }	    debug("run", "Running jobs before on ", $sshlogin->string(), ": ",		  $sshlogin->jobs_running(), "\n");	    if ($sshlogin->jobs_running() < $sshlogin->max_jobs_running()) {		if($opt::load and $sshlogin->loadavg_too_high()) {		    # The load is too high or unknown		    next;		}		if($opt::noswap and $sshlogin->swapping()) {		    # The server is swapping		    next;		}		if($sshlogin->too_fast_remote_login()) {		    # It has been too short since		    next;		}		if($opt::delay and $opt::delay > ::now() - $Global::newest_starttime) {		    # It has been too short since last start		    next;		}		debug("run", $sshlogin->string(), " has ", $sshlogin->jobs_running(),		      " out of ", $sshlogin->max_jobs_running(),		      " jobs running. Start another.\n");		if(start_another_job($sshlogin) == 0) {		    # No more jobs to start on this $sshlogin		    debug("run","No jobs started on ", $sshlogin->string(), "\n");		    next;		}		$sshlogin->inc_jobs_running();		$sshlogin->set_last_login_at(::now());		$jobs_started++;		$jobs_started_this_round++;	    }	    debug("run","Running jobs after on ", $sshlogin->string(), ": ",		  $sshlogin->jobs_running(), " of ",		  $sshlogin->max_jobs_running(), "\n");	}    } while($jobs_started_this_round);    return $jobs_started;}}{    my $no_more_file_handles_warned;sub start_another_job {    # If there are enough filehandles    #   and JobQueue not empty    #   and not $job is in joblog    # Then grab a job from Global::JobQueue,    #   start it at sshlogin    #   mark it as virgin_job    # Inputs:    #   $sshlogin = the SSHLogin to start the job on    # Uses:    #   $Global::JobQueue    #   $opt::pipe    #   $opt::results    #   $opt::resume    #   @Global::virgin_jobs    # Returns:    #   1 if another jobs was started    #   0 otherwise    my $sshlogin = shift;    # Do we have enough file handles to start another job?    if(enough_file_handles()) {        if($Global::JobQueue->empty() and not $opt::pipe) {            # No more commands to run	    debug("start", "Not starting: JobQueue empty\n");	    return 0;        } else {            my $job;	    # Skip jobs already in job log	    # Skip jobs already in results            do {		$job = get_job_with_sshlogin($sshlogin);		if(not defined $job) {		    # No command available for that sshlogin		    debug("start", "Not starting: no jobs available for ",			  $sshlogin->string(), "\n");		    return 0;		}	    } while ($job->is_already_in_joblog()		     or		     ($opt::results and $opt::resume and $job->is_already_in_results()));	    debug("start", "Command to run on '", $job->sshlogin()->string(), "': '",		  $job->replaced(),"'\n");            if($job->start()) {		if($opt::pipe) {		    push(@Global::virgin_jobs,$job);		}                debug("start", "Started as seq ", $job->seq(),		      " pid:", $job->pid(), "\n");                return 1;            } else {                # Not enough processes to run the job.		# Put it back on the queue.		$Global::JobQueue->unget($job);		# Count down the number of jobs to run for this SSHLogin.		my $max = $sshlogin->max_jobs_running();		if($max > 1) { $max--; } else {		    ::error("No more processes: cannot run a single job. Something is wrong.\n");		    ::wait_and_exit(255);		}		$sshlogin->set_max_jobs_running($max);		# Sleep up to 300 ms to give other processes time to die		::usleep(rand()*300);		::warning("No more processes: ",			  "Decreasing number of running jobs to $max. ",			  "Raising ulimit -u or /etc/security/limits.conf may help.\n");		return 0;            }        }    } else {        # No more file handles	$no_more_file_handles_warned++ or	    ::warning("No more file handles. ",		      "Raising ulimit -n or /etc/security/limits.conf may help.\n");        return 0;    }}}sub init_progress {    # Uses:    #   $opt::bar    # Returns:    #   list of computers for progress output    $|=1;    if($opt::bar) {	return("","");    }    my %progress = progress();    return ("\nComputers / CPU cores / Max jobs to run\n",            $progress{'workerlist'});}sub drain_job_queue {    # Uses:    #   $opt::progress    #   $Global::original_stderr    #   $Global::total_running    #   $Global::max_jobs_running    #   %Global::running    #   $Global::JobQueue    #   %Global::host    #   $Global::start_no_new_jobs    # Returns: N/A    if($opt::progress) {        print $Global::original_stderr init_progress();    }    my $last_header="";    my $sleep = 0.2;    do {        while($Global::total_running > 0) {            debug($Global::total_running, "==", scalar		  keys %Global::running," slots: ", $Global::max_jobs_running);	    if($opt::pipe) {		# When using --pipe sometimes file handles are not closed properly		for my $job (values %Global::running) {		    close $job->fh(0,"w");		}	    }            if($opt::progress) {                my %progress = progress();                if($last_header ne $progress{'header'}) {                    print $Global::original_stderr "\n", $progress{'header'}, "\n";                    $last_header = $progress{'header'};                }                print $Global::original_stderr "\r",$progress{'status'};		flush $Global::original_stderr;            }	    if($Global::total_running < $Global::max_jobs_running	       and not $Global::JobQueue->empty()) {		# These jobs may not be started because of loadavg		# or too little time between each ssh login.		if(start_more_jobs() > 0) {		    # Exponential back-on if jobs were started		    $sleep = $sleep/2+0.001;		}	    }            # Sometimes SIGCHLD is not registered, so force reaper	    $sleep = ::reap_usleep($sleep);        }        if(not $Global::JobQueue->empty()) {	    # These jobs may not be started:	    # * because there the --filter-hosts has removed all	    if(not %Global::host) {		::error("There are no hosts left to run on.\n");		::wait_and_exit(255);	    }	    # * because of loadavg	    # * because of too little time between each ssh login.            start_more_jobs();	    $sleep = ::reap_usleep($sleep);	    if($Global::max_jobs_running == 0) {		::warning("There are no job slots available. Increase --jobs.\n");	    }        }    } while ($Global::total_running > 0	     or	     not $Global::start_no_new_jobs and not $Global::JobQueue->empty());    if($opt::progress) {	my %progress = progress();	print $Global::original_stderr "\r", $progress{'status'}, "\n";	flush $Global::original_stderr;    }}sub toggle_progress {    # Turn on/off progress view    # Uses:    #   $opt::progress    #   $Global::original_stderr    # Returns: N/A    $opt::progress = not $opt::progress;    if($opt::progress) {        print $Global::original_stderr init_progress();    }}sub progress {    # Uses:    #   $opt::bar    #   $opt::eta    #   %Global::host    #   $Global::total_started    # Returns:    #   $workerlist = list of workers    #   $header = that will fit on the screen    #   $status = message that will fit on the screen    if($opt::bar) {	return ("workerlist" => "", "header" => "", "status" => bar());    }    my $eta = "";    my ($status,$header)=("","");    if($opt::eta) {	my($total, $completed, $left, $pctcomplete, $avgtime, $this_eta) =	    compute_eta();	$eta = sprintf("ETA: %ds Left: %d AVG: %.2fs  ",		       $this_eta, $left, $avgtime);    }    my $termcols = terminal_columns();    my @workers = sort keys %Global::host;    my %sshlogin = map { $_ eq ":" ? ($_=>"local") : ($_=>$_) } @workers;    my $workerno = 1;    my %workerno = map { ($_=>$workerno++) } @workers;    my $workerlist = "";    for my $w (@workers) {        $workerlist .=        $workerno{$w}.":".$sshlogin{$w} ." / ".            ($Global::host{$w}->ncpus() || "-")." / ".            $Global::host{$w}->max_jobs_running()."\n";    }    $status = "x"x($termcols+1);    if(length $status > $termcols) {        # sshlogin1:XX/XX/XX%/XX.Xs sshlogin2:XX/XX/XX%/XX.Xs sshlogin3:XX/XX/XX%/XX.Xs        $header = "Computer:jobs running/jobs completed/%of started jobs/Average seconds to complete";        $status = $eta .            join(" ",map                 {                     if($Global::total_started) {                         my $completed = ($Global::host{$_}->jobs_completed()||0);                         my $running = $Global::host{$_}->jobs_running();                         my $time = $completed ? (time-$^T)/($completed) : "0";                         sprintf("%s:%d/%d/%d%%/%.1fs ",                                 $sshlogin{$_}, $running, $completed,                                 ($running+$completed)*100                                 / $Global::total_started, $time);                     }                 } @workers);    }    if(length $status > $termcols) {        # 1:XX/XX/XX%/XX.Xs 2:XX/XX/XX%/XX.Xs 3:XX/XX/XX%/XX.Xs 4:XX/XX/XX%/XX.Xs        $header = "Computer:jobs running/jobs completed/%of started jobs";        $status = $eta .            join(" ",map                 {                     my $completed = ($Global::host{$_}->jobs_completed()||0);                     my $running = $Global::host{$_}->jobs_running();                     my $time = $completed ? (time-$^T)/($completed) : "0";                     sprintf("%s:%d/%d/%d%%/%.1fs ",                             $workerno{$_}, $running, $completed,                             ($running+$completed)*100                             / $Global::total_started, $time);                 } @workers);    }    if(length $status > $termcols) {        # sshlogin1:XX/XX/XX% sshlogin2:XX/XX/XX% sshlogin3:XX/XX/XX%        $header = "Computer:jobs running/jobs completed/%of started jobs";        $status = $eta .            join(" ",map                 { sprintf("%s:%d/%d/%d%%",                           $sshlogin{$_},                           $Global::host{$_}->jobs_running(),                           ($Global::host{$_}->jobs_completed()||0),                           ($Global::host{$_}->jobs_running()+                            ($Global::host{$_}->jobs_completed()||0))*100                           / $Global::total_started) }                 @workers);    }    if(length $status > $termcols) {        # 1:XX/XX/XX% 2:XX/XX/XX% 3:XX/XX/XX% 4:XX/XX/XX% 5:XX/XX/XX% 6:XX/XX/XX%        $header = "Computer:jobs running/jobs completed/%of started jobs";        $status = $eta .            join(" ",map                 { sprintf("%s:%d/%d/%d%%",                           $workerno{$_},                           $Global::host{$_}->jobs_running(),                           ($Global::host{$_}->jobs_completed()||0),                           ($Global::host{$_}->jobs_running()+                            ($Global::host{$_}->jobs_completed()||0))*100                           / $Global::total_started) }                 @workers);    }    if(length $status > $termcols) {        # sshlogin1:XX/XX/XX% sshlogin2:XX/XX/XX% sshlogin3:XX/XX sshlogin4:XX/XX        $header = "Computer:jobs running/jobs completed";        $status = $eta .            join(" ",map                       { sprintf("%s:%d/%d",                                 $sshlogin{$_}, $Global::host{$_}->jobs_running(),                                 ($Global::host{$_}->jobs_completed()||0)) }                       @workers);    }    if(length $status > $termcols) {        # sshlogin1:XX/XX sshlogin2:XX/XX sshlogin3:XX/XX sshlogin4:XX/XX        $header = "Computer:jobs running/jobs completed";        $status = $eta .            join(" ",map                       { sprintf("%s:%d/%d",                                 $sshlogin{$_}, $Global::host{$_}->jobs_running(),                                 ($Global::host{$_}->jobs_completed()||0)) }                       @workers);    }    if(length $status > $termcols) {        # 1:XX/XX 2:XX/XX 3:XX/XX 4:XX/XX 5:XX/XX 6:XX/XX        $header = "Computer:jobs running/jobs completed";        $status = $eta .            join(" ",map                       { sprintf("%s:%d/%d",                                 $workerno{$_}, $Global::host{$_}->jobs_running(),                                 ($Global::host{$_}->jobs_completed()||0)) }                       @workers);    }    if(length $status > $termcols) {        # sshlogin1:XX sshlogin2:XX sshlogin3:XX sshlogin4:XX sshlogin5:XX        $header = "Computer:jobs completed";        $status = $eta .            join(" ",map                       { sprintf("%s:%d",                                 $sshlogin{$_},                                 ($Global::host{$_}->jobs_completed()||0)) }                       @workers);    }    if(length $status > $termcols) {        # 1:XX 2:XX 3:XX 4:XX 5:XX 6:XX        $header = "Computer:jobs completed";        $status = $eta .            join(" ",map                       { sprintf("%s:%d",                                 $workerno{$_},                                 ($Global::host{$_}->jobs_completed()||0)) }                       @workers);    }    return ("workerlist" => $workerlist, "header" => $header, "status" => $status);}{    my ($total, $first_completed, $smoothed_avg_time);    sub compute_eta {	# Calculate important numbers for ETA	# Returns:	#   $total = number of jobs in total	#   $completed = number of jobs completed	#   $left = number of jobs left	#   $pctcomplete = percent of jobs completed	#   $avgtime = averaged time	#   $eta = smoothed eta	$total ||= $Global::JobQueue->total_jobs();	my $completed = 0;        for(values %Global::host) { $completed += $_->jobs_completed() }	my $left = $total - $completed;	if(not $completed) {	    return($total, $completed, $left, 0, 0, 0);	}	my $pctcomplete = $completed / $total;	$first_completed ||= time;	my $timepassed = (time - $first_completed);	my $avgtime = $timepassed / $completed;	$smoothed_avg_time ||= $avgtime;	# Smooth the eta so it does not jump wildly	$smoothed_avg_time = (1 - $pctcomplete) * $smoothed_avg_time +	    $pctcomplete * $avgtime;	my $eta = int($left * $smoothed_avg_time);	return($total, $completed, $left, $pctcomplete, $avgtime, $eta);    }}{    my ($rev,$reset);    sub bar {	# Return:	#   $status = bar with eta, completed jobs, arg and pct	$rev ||= "\033[7m";	$reset ||= "\033[0m";	my($total, $completed, $left, $pctcomplete, $avgtime, $eta) =	    compute_eta();	my $arg = $Global::newest_job ?	    $Global::newest_job->{'commandline'}->replace_placeholders(["\257<\257>"],0,0) : "";	# These chars mess up display in the terminal	$arg =~ tr/[\011-\016\033\302-\365]//d;	my $bar_text =	    sprintf("%d%% %d:%d=%ds %s",		    $pctcomplete*100, $completed, $left, $eta, $arg);	my $terminal_width = terminal_columns();	my $s = sprintf("%-${terminal_width}s",			substr($bar_text." "x$terminal_width,			       0,$terminal_width));	my $width = int($terminal_width * $pctcomplete);	substr($s,$width,0) = $reset;	my $zenity = sprintf("%-${terminal_width}s",			     substr("#   $eta sec $arg",				    0,$terminal_width));	$s = "\r" . $zenity . "\r" . $pctcomplete*100 . # Prefix with zenity header	    "\r" . $rev . $s . $reset;	return $s;    }}{    my ($columns,$last_column_time);    sub terminal_columns {	# Get the number of columns of the display	# Returns:	#   number of columns of the screen	if(not $columns or $last_column_time < time) {	    $last_column_time = time;	    $columns = $ENV{'COLUMNS'};	    if(not $columns) {		my $resize = qx{ resize 2>/dev/null };		$resize =~ /COLUMNS=(\d+);/ and do { $columns = $1; };	    }	    $columns ||= 80;	}	return $columns;    }}sub get_job_with_sshlogin {    # Returns:    #   next job object for $sshlogin if any available    my $sshlogin = shift;    my $job = undef;    if ($opt::hostgroups) {	my @other_hostgroup_jobs = ();        while($job = $Global::JobQueue->get()) {	    if($sshlogin->in_hostgroups($job->hostgroups())) {		# Found a job for this hostgroup		last;	    } else {		# This job was not in the hostgroups of $sshlogin                push @other_hostgroup_jobs, $job;            }        }	$Global::JobQueue->unget(@other_hostgroup_jobs);	if(not defined $job) {	    # No more jobs	    return undef;	}    } else {        $job = $Global::JobQueue->get();        if(not defined $job) {            # No more jobs	    ::debug("start", "No more jobs: JobQueue empty\n");            return undef;        }    }    my $clean_command = $job->replaced();    if($clean_command =~ /^\s*$/) {        # Do not run empty lines        if(not $Global::JobQueue->empty()) {            return get_job_with_sshlogin($sshlogin);        } else {            return undef;        }    }    $job->set_sshlogin($sshlogin);    if($opt::retries and $clean_command and       $job->failed_here()) {        # This command with these args failed for this sshlogin        my ($no_of_failed_sshlogins,$min_failures) = $job->min_failed();	# Only look at the Global::host that have > 0 jobslots        if($no_of_failed_sshlogins == grep { $_->max_jobs_running() > 0 } values %Global::host	   and $job->failed_here() == $min_failures) {            # It failed the same or more times on another host:            # run it on this host        } else {            # If it failed fewer times on another host:            # Find another job to run            my $nextjob;            if(not $Global::JobQueue->empty()) {		# This can potentially recurse for all args                no warnings 'recursion';                $nextjob = get_job_with_sshlogin($sshlogin);            }            # Push the command back on the queue            $Global::JobQueue->unget($job);            return $nextjob;        }    }    return $job;}sub __REMOTE_SSH__ {}sub read_sshloginfiles {    # Returns: N/A    for my $s (@_) {	read_sshloginfile(expand_slf_shorthand($s));    }}sub expand_slf_shorthand {    my $file = shift;    if($file eq "-") {	# skip: It is stdin    } elsif($file eq "..") {        $file = $ENV{'HOME'}."/.parallel/sshloginfile";    } elsif($file eq ".") {        $file = "/etc/parallel/sshloginfile";    } elsif(not -r $file) {	if(not -r $ENV{'HOME'}."/.parallel/".$file) {		# Try prepending ~/.parallel		::error("Cannot open $file.\n");		::wait_and_exit(255);	} else {	    $file = $ENV{'HOME'}."/.parallel/".$file;	}    }    return $file;}sub read_sshloginfile {    # Returns: N/A    my $file = shift;    my $close = 1;    my $in_fh;    ::debug("init","--slf ",$file);    if($file eq "-") {	$in_fh = *STDIN;	$close = 0;    } else {	if(not open($in_fh, "<", $file)) {	    # Try the filename	    ::error("Cannot open $file.\n");	    ::wait_and_exit(255);	}    }    while(<$in_fh>) {        chomp;        /^\s*#/ and next;        /^\s*$/ and next;        push @Global::sshlogin, $_;    }    if($close) {	close $in_fh;    }}sub parse_sshlogin {    # Returns: N/A    my @login;    if(not @Global::sshlogin) { @Global::sshlogin = (":"); }    for my $sshlogin (@Global::sshlogin) {        # Split up -S sshlogin,sshlogin        for my $s (split /,/, $sshlogin) {            if ($s eq ".." or $s eq "-") {		# This may add to @Global::sshlogin - possibly bug		read_sshloginfile(expand_slf_shorthand($s));            } else {                push (@login, $s);            }        }    }    $Global::minimal_command_line_length = 8_000_000;    my @allowed_hostgroups;    for my $ncpu_sshlogin_string (::uniq(@login)) {	my $sshlogin = SSHLogin->new($ncpu_sshlogin_string);	my $sshlogin_string = $sshlogin->string();	if($sshlogin_string eq "") {	    # This is an ssh group: -S @webservers	    push @allowed_hostgroups, $sshlogin->hostgroups();	    next;	}	if($Global::host{$sshlogin_string}) {	    # This sshlogin has already been added:	    # It is probably a host that has come back	    # Set the max_jobs_running back to the original	    debug("run","Already seen $sshlogin_string\n");	    if($sshlogin->{'ncpus'}) {		# If ncpus set by '#/' of the sshlogin, overwrite it:		$Global::host{$sshlogin_string}->set_ncpus($sshlogin->ncpus());	    }	    $Global::host{$sshlogin_string}->set_max_jobs_running(undef);	    next;	}	if($sshlogin_string eq ":") {	    $sshlogin->set_maxlength(Limits::Command::max_length());	} else {	    # If all chars needs to be quoted, every other character will be \	    $sshlogin->set_maxlength(int(Limits::Command::max_length()/2));	}	$Global::minimal_command_line_length =	    ::min($Global::minimal_command_line_length, $sshlogin->maxlength());        $Global::host{$sshlogin_string} = $sshlogin;    }    if(@allowed_hostgroups) {	# Remove hosts that are not in these groups	while (my ($string, $sshlogin) = each %Global::host) {	    if(not $sshlogin->in_hostgroups(@allowed_hostgroups)) {		delete $Global::host{$string};	    }	}    }    # debug("start", "sshlogin: ", my_dump(%Global::host),"\n");    if($opt::transfer or @opt::return or $opt::cleanup or @opt::basefile) {        if(not remote_hosts()) {            # There are no remote hosts            if(@opt::trc) {		::warning("--trc ignored as there are no remote --sshlogin.\n");            } elsif (defined $opt::transfer) {		::warning("--transfer ignored as there are no remote --sshlogin.\n");            } elsif (@opt::return) {                ::warning("--return ignored as there are no remote --sshlogin.\n");            } elsif (defined $opt::cleanup) {		::warning("--cleanup ignored as there are no remote --sshlogin.\n");            } elsif (@opt::basefile) {                ::warning("--basefile ignored as there are no remote --sshlogin.\n");            }        }    }}sub remote_hosts {    # Return sshlogins that are not ':'    # Returns:    #   list of sshlogins with ':' removed    return grep !/^:$/, keys %Global::host;}sub setup_basefile {    # Transfer basefiles to each $sshlogin    # This needs to be done before first jobs on $sshlogin is run    # Returns: N/A    my $cmd = "";    my $rsync_destdir;    my $workdir;    for my $sshlogin (values %Global::host) {      if($sshlogin->string() eq ":") { next }      for my $file (@opt::basefile) {	if($file !~ m:^/: and $opt::workdir eq "...") {	  ::error("Work dir '...' will not work with relative basefiles\n");	  ::wait_and_exit(255);	}	$workdir ||= Job->new("")->workdir();	$cmd .= $sshlogin->rsync_transfer_cmd($file,$workdir) . "&";      }    }    $cmd .= "wait;";    debug("init", "basesetup: $cmd\n");    print `$cmd`;}sub cleanup_basefile {    # Remove the basefiles transferred    # Returns: N/A    my $cmd="";    my $workdir = Job->new("")->workdir();    for my $sshlogin (values %Global::host) {        if($sshlogin->string() eq ":") { next }        for my $file (@opt::basefile) {	  $cmd .= $sshlogin->cleanup_cmd($file,$workdir)."&";        }    }    $cmd .= "wait;";    debug("init", "basecleanup: $cmd\n");    print `$cmd`;}sub filter_hosts {    my(@cores, @cpus, @maxline, @echo);    my $envvar = ::shell_quote_scalar($Global::envvar);    while (my ($host, $sshlogin) = each %Global::host) {	if($host eq ":") { next }	# The 'true' is used to get the $host out later	my $sshcmd = "true $host;" . $sshlogin->sshcommand()." ".$sshlogin->serverlogin();	push(@cores, $host."\t".$sshcmd." ".$envvar." parallel --number-of-cores\n\0");	push(@cpus, $host."\t".$sshcmd." ".$envvar." parallel --number-of-cpus\n\0");	push(@maxline, $host."\t".$sshcmd." ".$envvar." parallel --max-line-length-allowed\n\0");	# 'echo' is used to get the best possible value for an ssh login time	push(@echo, $host."\t".$sshcmd." echo\n\0");    }    my ($fh, $tmpfile) = ::tmpfile(SUFFIX => ".ssh");    print $fh @cores, @cpus, @maxline, @echo;    close $fh;    # --timeout 5: Setting up an SSH connection and running a simple    #              command should never take > 5 sec.    # --delay 0.1: If multiple sshlogins use the same proxy the delay    #              will make it less likely to overload the ssh daemon.    # --retries 3: If the ssh daemon it overloaded, try 3 times    # -s 16000: Half of the max line on UnixWare    my $cmd = "cat $tmpfile | $0 -j0 --timeout 5 -s 16000 --joblog - --plain --delay 0.1 --retries 3 --tag --tagstring {1} -0 --colsep '\t' -k eval {2} 2>/dev/null";    ::debug("init", $cmd, "\n");    open(my $host_fh, "-|", $cmd) || ::die_bug("parallel host check: $cmd");    my (%ncores, %ncpus, %time_to_login, %maxlen, %echo, @down_hosts);    my $prepend = "";    while(<$host_fh>) {	if(/\'$/) {	    # if last char = ' then append next line	    # This may be due to quoting of $Global::envvar	    $prepend .= $_;	    next;	}	$_ = $prepend . $_;	$prepend = "";	chomp;	my @col = split /\t/, $_;	if(defined $col[6]) {	    # This is a line from --joblog	    # seq host time spent sent received exit signal command	    # 2 : 1372607672.654 0.675 0 0 0 0 eval true\ m\;ssh\ m\ parallel\ --number-of-cores	    if($col[0] eq "Seq" and $col[1] eq "Host" and		    $col[2] eq "Starttime") {		# Header => skip		next;	    }	    # Get server from: eval true server\;	    $col[8] =~ /eval true..([^;]+).;/ or ::die_bug("col8 does not contain host: $col[8]");	    my $host = $1;	    $host =~ tr/\\//d;	    $Global::host{$host} or next;	    if($col[6] eq "255" or $col[7] eq "15") {		# exit == 255 or signal == 15: ssh failed		# Remove sshlogin		::debug("init", "--filtered $host\n");		push(@down_hosts, $host);		@down_hosts = uniq(@down_hosts);	    } elsif($col[6] eq "127") {		# signal == 127: parallel not installed remote		# Set ncpus and ncores = 1		::warning("Could not figure out ",			  "number of cpus on $host. Using 1.\n");		$ncores{$host} = 1;		$ncpus{$host} = 1;		$maxlen{$host} = Limits::Command::max_length();	    } elsif($col[0] =~ /^\d+$/ and $Global::host{$host}) {		# Remember how log it took to log in		# 2 : 1372607672.654 0.675 0 0 0 0 eval true\ m\;ssh\ m\ echo		$time_to_login{$host} = ::min($time_to_login{$host},$col[3]);	    } else {		::die_bug("host check unmatched long jobline: $_");	    }	} elsif($Global::host{$col[0]}) {	    # This output from --number-of-cores, --number-of-cpus,	    # --max-line-length-allowed	    # ncores: server       8	    # ncpus:  server       2	    # maxlen: server       131071	    if(not $ncores{$col[0]}) {		$ncores{$col[0]} = $col[1];	    } elsif(not $ncpus{$col[0]}) {		$ncpus{$col[0]} = $col[1];	    } elsif(not $maxlen{$col[0]}) {		$maxlen{$col[0]} = $col[1];	    } elsif(not $echo{$col[0]}) {		$echo{$col[0]} = $col[1];	    } elsif(m/perl: warning:|LANGUAGE =|LC_ALL =|LANG =|are supported and installed/) {		# Skip these:		# perl: warning: Setting locale failed.		# perl: warning: Please check that your locale settings:		#         LANGUAGE = (unset),		#         LC_ALL = (unset),		#         LANG = "en_US.UTF-8"		#     are supported and installed on your system.		# perl: warning: Falling back to the standard locale ("C").	    } else {		::die_bug("host check too many col0: $_");	    }	} else {	    ::die_bug("host check unmatched short jobline ($col[0]): $_");	}    }    close $host_fh;    $Global::debug or unlink $tmpfile;    delete @Global::host{@down_hosts};    @down_hosts and ::warning("Removed @down_hosts\n");    $Global::minimal_command_line_length = 8_000_000;    while (my ($sshlogin, $obj) = each %Global::host) {	if($sshlogin eq ":") { next }	$ncpus{$sshlogin} or ::die_bug("ncpus missing: ".$obj->serverlogin());	$ncores{$sshlogin} or ::die_bug("ncores missing: ".$obj->serverlogin());	$time_to_login{$sshlogin} or ::die_bug("time_to_login missing: ".$obj->serverlogin());	$maxlen{$sshlogin} or ::die_bug("maxlen missing: ".$obj->serverlogin());	if($opt::use_cpus_instead_of_cores) {	    $obj->set_ncpus($ncpus{$sshlogin});	} else {	    $obj->set_ncpus($ncores{$sshlogin});	}	$obj->set_time_to_login($time_to_login{$sshlogin});        $obj->set_maxlength($maxlen{$sshlogin});	$Global::minimal_command_line_length =	    ::min($Global::minimal_command_line_length,		  int($maxlen{$sshlogin}/2));	::debug("init", "Timing from -S:$sshlogin ncpus:",$ncpus{$sshlogin},		" ncores:", $ncores{$sshlogin},		" time_to_login:", $time_to_login{$sshlogin},		" maxlen:", $maxlen{$sshlogin},		" min_max_len:", $Global::minimal_command_line_length,"\n");    }}sub onall {    sub tmp_joblog {	my $joblog = shift;	if(not defined $joblog) {	    return undef;	}	my ($fh, $tmpfile) = ::tmpfile(SUFFIX => ".log");	close $fh;	return $tmpfile;    }    my @command = @_;    if($Global::quoting) {       @command = shell_quote_empty(@command);    }    # Copy all @fhlist into tempfiles    my @argfiles = ();    for my $fh (@fhlist) {	my ($outfh, $name) = ::tmpfile(SUFFIX => ".all", UNLINK => 1);	print $outfh (<$fh>);	close $outfh;	push @argfiles, $name;    }    if(@opt::basefile) { setup_basefile(); }    # for each sshlogin do:    # parallel -S $sshlogin $command :::: @argfiles    #    # Pass some of the options to the sub-parallels, not all of them as    # -P should only go to the first, and -S should not be copied at all.    my $options =	join(" ",	     ((defined $opt::jobs) ? "-P $opt::jobs" : ""),	     ((defined $opt::linebuffer) ? "--linebuffer" : ""),	     ((defined $opt::ungroup) ? "-u" : ""),	     ((defined $opt::group) ? "-g" : ""),	     ((defined $opt::keeporder) ? "--keeporder" : ""),	     ((defined $opt::D) ? "-D $opt::D" : ""),	     ((defined $opt::plain) ? "--plain" : ""),	     ((defined $opt::max_chars) ? "--max-chars ".$opt::max_chars : ""),	);    my $suboptions =	join(" ",	     ((defined $opt::ungroup) ? "-u" : ""),	     ((defined $opt::linebuffer) ? "--linebuffer" : ""),	     ((defined $opt::group) ? "-g" : ""),	     ((defined $opt::files) ? "--files" : ""),	     ((defined $opt::keeporder) ? "--keeporder" : ""),	     ((defined $opt::colsep) ? "--colsep ".shell_quote($opt::colsep) : ""),	     ((@opt::v) ? "-vv" : ""),	     ((defined $opt::D) ? "-D $opt::D" : ""),	     ((defined $opt::timeout) ? "--timeout ".$opt::timeout : ""),	     ((defined $opt::plain) ? "--plain" : ""),	     ((defined $opt::retries) ? "--retries ".$opt::retries : ""),	     ((defined $opt::max_chars) ? "--max-chars ".$opt::max_chars : ""),	     ((defined $opt::arg_sep) ? "--arg-sep ".$opt::arg_sep : ""),	     ((defined $opt::arg_file_sep) ? "--arg-file-sep ".$opt::arg_file_sep : ""),	     (@opt::env ? map { "--env ".::shell_quote_scalar($_) } @opt::env : ""),	);    ::debug("init", "| $0 $options\n");    open(my $parallel_fh, "|-", "$0 --no-notice -j0 $options") ||	::die_bug("This does not run GNU Parallel: $0 $options");    my @joblogs;    for my $host (sort keys %Global::host) {	my $sshlogin = $Global::host{$host};	my $joblog = tmp_joblog($opt::joblog);	if($joblog) {	    push @joblogs, $joblog;	    $joblog = "--joblog $joblog";	}	my $quad = $opt::arg_file_sep || "::::";	::debug("init", "$0 $suboptions -j1 $joblog ",	    ((defined $opt::tag) ?	     "--tagstring ".shell_quote_scalar($sshlogin->string()) : ""),	     " -S ", shell_quote_scalar($sshlogin->string())," ",	     join(" ",shell_quote(@command))," $quad @argfiles\n");	print $parallel_fh "$0 $suboptions -j1 $joblog ",	    ((defined $opt::tag) ?	     "--tagstring ".shell_quote_scalar($sshlogin->string()) : ""),	     " -S ", shell_quote_scalar($sshlogin->string())," ",	     join(" ",shell_quote(@command))," $quad @argfiles\n";    }    close $parallel_fh;    $Global::exitstatus = $? >> 8;    debug("init", "--onall exitvalue ", $?);    if(@opt::basefile) { cleanup_basefile(); }    $Global::debug or unlink(@argfiles);    my %seen;    for my $joblog (@joblogs) {	# Append to $joblog	open(my $fh, "<", $joblog) || ::die_bug("Cannot open tmp joblog $joblog");	# Skip first line (header);	<$fh>;	print $Global::joblog (<$fh>);	close $fh;	unlink($joblog);    }}sub __SIGNAL_HANDLING__ {}sub save_original_signal_handler {    # Remember the original signal handler    # Returns: N/A    $SIG{TERM} ||= sub { exit 0; }; # $SIG{TERM} is not set on Mac OS X    $SIG{INT} = sub { if($opt::tmux) { qx { tmux kill-session -t p$$ }; }		      unlink keys %Global::unlink; exit -1  };    $SIG{TERM} = sub { if($opt::tmux) { qx { tmux kill-session -t p$$ }; }		      unlink keys %Global::unlink; exit -1  };    %Global::original_sig = %SIG;    $SIG{TERM} = sub {}; # Dummy until jobs really start}sub list_running_jobs {    # Returns: N/A    for my $v (values %Global::running) {        print $Global::original_stderr "$Global::progname: ",$v->replaced(),"\n";    }}sub start_no_new_jobs {    # Returns: N/A    $SIG{TERM} = $Global::original_sig{TERM};    print $Global::original_stderr        ("$Global::progname: SIGTERM received. No new jobs will be started.\n",         "$Global::progname: Waiting for these ", scalar(keys %Global::running),         " jobs to finish. Send SIGTERM again to stop now.\n");    list_running_jobs();    $Global::start_no_new_jobs ||= 1;}sub reaper {    # A job finished.    # Print the output.    # Start another job    # Returns: N/A    my $stiff;    my $children_reaped = 0;    debug("run", "Reaper ");    while (($stiff = waitpid(-1, &WNOHANG)) > 0) {	$children_reaped++;        if($Global::sshmaster{$stiff}) {            # This is one of the ssh -M: ignore            next;        }        my $job = $Global::running{$stiff};	# '-a <(seq 10)' will give us a pid not in %Global::running        $job or next;        $job->set_exitstatus($? >> 8);        $job->set_exitsignal($? & 127);        debug("run", "died (", $job->exitstatus(), "): ", $job->seq());        $job->set_endtime(::now());        if($stiff == $Global::tty_taken) {            # The process that died had the tty => release it            $Global::tty_taken = 0;        }        if(not $job->should_be_retried()) {	    # The job is done	    # Free the jobslot	    push @Global::slots, $job->slot();	    if($opt::timeout) {		# Update average runtime for timeout		$Global::timeoutq->update_delta_time($job->runtime());	    }            # Force printing now if the job failed and we are going to exit            my $print_now = ($opt::halt_on_error and $opt::halt_on_error == 2			     and $job->exitstatus());            if($opt::keeporder and not $print_now) {                print_earlier_jobs($job);            } else {                $job->print();            }            if($job->exitstatus()) {		process_failed_job($job);	    }        }        my $sshlogin = $job->sshlogin();        $sshlogin->dec_jobs_running();        $sshlogin->inc_jobs_completed();        $Global::total_running--;        delete $Global::running{$stiff};	start_more_jobs();    }    debug("run", "done ");    return $children_reaped;}sub process_failed_job {    # The jobs had a exit status <> 0, so error    # Returns: N/A    my $job = shift;    $Global::exitstatus++;    $Global::total_failed++;    if($opt::halt_on_error) {	if($opt::halt_on_error == 1	   or	   ($opt::halt_on_error < 1 and $Global::total_failed > 3	    and	    $Global::total_failed / $Global::total_started > $opt::halt_on_error)) {	    # If halt on error == 1 or --halt 10%	    # we should gracefully exit	    print $Global::original_stderr		("$Global::progname: Starting no more jobs. ",		 "Waiting for ", scalar(keys %Global::running),		 " jobs to finish. This job failed:\n",		 $job->replaced(),"\n");	    $Global::start_no_new_jobs ||= 1;	    $Global::halt_on_error_exitstatus = $job->exitstatus();	} elsif($opt::halt_on_error == 2) {	    # If halt on error == 2 we should exit immediately	    print $Global::original_stderr		("$Global::progname: This job failed:\n",		 $job->replaced(),"\n");	    exit ($job->exitstatus());	}    }}{    my (%print_later,$job_end_sequence);    sub print_earlier_jobs {	# Print jobs completed earlier	# Returns: N/A	my $job = shift;	$print_later{$job->seq()} = $job;	$job_end_sequence ||= 1;	debug("run", "Looking for: $job_end_sequence ",	      "Current: ", $job->seq(), "\n");	for(my $j = $print_later{$job_end_sequence};	    $j or vec($Global::job_already_run,$job_end_sequence,1);	    $job_end_sequence++,	    $j = $print_later{$job_end_sequence}) {	    debug("run", "Found job end $job_end_sequence");	    if($j) {		$j->print();		delete $print_later{$job_end_sequence};	    }	}    }}sub __USAGE__ {}sub wait_and_exit {    # If we do not wait, we sometimes get segfault    # Returns: N/A    my $error = shift;    if($error) {	# Kill all without printing	for my $job (values %Global::running) {	    $job->kill("TERM");	    $job->kill("TERM");	}    }    for (keys %Global::unkilled_children) {        kill 9, $_;        waitpid($_,0);        delete $Global::unkilled_children{$_};    }    wait();    exit($error);}sub die_usage {    # Returns: N/A    usage();    wait_and_exit(255);}sub usage {    # Returns: N/A    print join	("\n",	 "Usage:",	 "",	 "$Global::progname [options] [command [arguments]] < list_of_arguments",	 "$Global::progname [options] [command [arguments]] (::: arguments|:::: argfile(s))...",	 "cat ... | $Global::progname --pipe [options] [command [arguments]]",	 "",	 "-j n            Run n jobs in parallel",	 "-k              Keep same order",	 "-X              Multiple arguments with context replace",	 "--colsep regexp Split input on regexp for positional replacements",	 "{} {.} {/} {/.} {#} {%} {= perl code =} Replacement strings",	 "{3} {3.} {3/} {3/.} {=3 perl code =}    Positional replacement strings",	 "With --plus:    {} = {+/}/{/} = {.}.{+.} = {+/}/{/.}.{+.} = {..}.{+..} =",	 "                {+/}/{/..}.{+..} = {...}.{+...} = {+/}/{/...}.{+...}",	 "",	 "-S sshlogin     Example: foo\@server.example.com",	 "--slf ..        Use ~/.parallel/sshloginfile as the list of sshlogins",	 "--trc {}.bar    Shorthand for --transfer --return {}.bar --cleanup",	 "--onall         Run the given command with argument on all sshlogins",	 "--nonall        Run the given command with no arguments on all sshlogins",	 "",	 "--pipe          Split stdin (standard input) to multiple jobs.",	 "--recend str    Record end separator for --pipe.",	 "--recstart str  Record start separator for --pipe.",	 "",	 "See 'man $Global::progname' for details",	 "",	 "When using programs that use GNU Parallel to process data for publication please cite:",	 "",	 "O. Tange (2011): GNU Parallel - The Command-Line Power Tool,",	 ";login: The USENIX Magazine, February 2011:42-47.",	 "",	 "Or you can get GNU Parallel without this requirement by paying 10000 EUR.",	 "");}sub citation_notice {    # if --no-notice or --plain: do nothing    # if stderr redirected: do nothing    # if ~/.parallel/will-cite: do nothing    # else: print citation notice to stderr    if($opt::no_notice       or       $opt::plain       or       not -t $Global::original_stderr       or       -e $ENV{'HOME'}."/.parallel/will-cite") {	# skip    } else {	print $Global::original_stderr	    ("When using programs that use GNU Parallel to process data for publication please cite:\n",	     "\n",	     "  O. Tange (2011): GNU Parallel - The Command-Line Power Tool,\n",	     "  ;login: The USENIX Magazine, February 2011:42-47.\n",	     "\n",	     "This helps funding further development; and it won't cost you a cent.\n",	     "Or you can get GNU Parallel without this requirement by paying 10000 EUR.\n",	     "\n",	     "To silence this citation notice run 'parallel --bibtex' once or use '--no-notice'.\n\n",	    );	flush $Global::original_stderr;    }}sub warning {    my @w = @_;    my $fh = $Global::original_stderr || *STDERR;    my $prog = $Global::progname || "parallel";    print $fh $prog, ": Warning: ", @w;}sub error {    my @w = @_;    my $fh = $Global::original_stderr || *STDERR;    my $prog = $Global::progname || "parallel";    print $fh $prog, ": Error: ", @w;}sub die_bug {    my $bugid = shift;    print STDERR	("$Global::progname: This should not happen. You have found a bug.\n",	 "Please contact <parallel\@gnu.org> and include:\n",	 "* The version number: $Global::version\n",	 "* The bugid: $bugid\n",	 "* The command line being run\n",	 "* The files being read (put the files on a webserver if they are big)\n",	 "\n",	 "If you get the error on smaller/fewer files, please include those instead.\n");    ::wait_and_exit(255);}sub version {    # Returns: N/A    if($opt::tollef and not $opt::gnu) {	print "WARNING: YOU ARE USING --tollef. IF THINGS ARE ACTING WEIRD USE --gnu.\n";    }    print join("\n",               "GNU $Global::progname $Global::version",               "Copyright (C) 2007,2008,2009,2010,2011,2012,2013,2014 Ole Tange and Free Software Foundation, Inc.",               "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>",               "This is free software: you are free to change and redistribute it.",               "GNU $Global::progname comes with no warranty.",               "",               "Web site: http://www.gnu.org/software/${Global::progname}\n",	       "When using programs that use GNU Parallel to process data for publication please cite:\n",	       "O. Tange (2011): GNU Parallel - The Command-Line Power Tool, ",	       ";login: The USENIX Magazine, February 2011:42-47.\n",	       "Or you can get GNU Parallel without this requirement by paying 10000 EUR.\n",        );}sub bibtex {    # Returns: N/A    if($opt::tollef and not $opt::gnu) {	print "WARNING: YOU ARE USING --tollef. IF THINGS ARE ACTING WEIRD USE --gnu.\n";    }    print join("\n",	       "When using programs that use GNU Parallel to process data for publication please cite:",	       "",               "\@article{Tange2011a,",	       " title = {GNU Parallel - The Command-Line Power Tool},",	       " author = {O. Tange},",	       " address = {Frederiksberg, Denmark},",	       " journal = {;login: The USENIX Magazine},",	       " month = {Feb},",	       " number = {1},",	       " volume = {36},",	       " url = {http://www.gnu.org/s/parallel},",	       " year = {2011},",	       " pages = {42-47}",	       "}",	       "",	       "(Feel free to use \\nocite{Tange2011a})",	       "",	       "This helps funding further development.",	       "",	       "Or you can get GNU Parallel without this requirement by paying 10000 EUR.",	       ""        );    while(not -e $ENV{'HOME'}."/.parallel/will-cite") {	print "\nType: 'will cite' and press enter.\n> ";	my $input = <STDIN>;	if($input =~ /will cite/i) {	    mkdir $ENV{'HOME'}."/.parallel";	    open (my $fh, ">", $ENV{'HOME'}."/.parallel/will-cite")		|| ::die_bug("Cannot write: ".$ENV{'HOME'}."/.parallel/will-cite");	    close $fh;	    print "\nThank you for your support. It is much appreciated. The citation\n",	    "notice is now silenced.\n";	}    }}sub show_limits {    # Returns: N/A    print("Maximal size of command: ",Limits::Command::real_max_length(),"\n",          "Maximal used size of command: ",Limits::Command::max_length(),"\n",          "\n",          "Execution of  will continue now, and it will try to read its input\n",          "and run commands; if this is not what you wanted to happen, please\n",          "press CTRL-D or CTRL-C\n");}sub __GENERIC_COMMON_FUNCTION__ {}sub uniq {    # Remove duplicates and return unique values    return keys %{{ map { $_ => 1 } @_ }};}sub min {    # Returns:    #   Minimum value of array    my $min;    for (@_) {        # Skip undefs        defined $_ or next;        defined $min or do { $min = $_; next; }; # Set $_ to the first non-undef        $min = ($min < $_) ? $min : $_;    }    return $min;}sub max {    # Returns:    #   Maximum value of array    my $max;    for (@_) {        # Skip undefs        defined $_ or next;        defined $max or do { $max = $_; next; }; # Set $_ to the first non-undef        $max = ($max > $_) ? $max : $_;    }    return $max;}sub sum {    # Returns:    #   Sum of values of array    my @args = @_;    my $sum = 0;    for (@args) {        # Skip undefs        $_ and do { $sum += $_; }    }    return $sum;}sub undef_as_zero {    my $a = shift;    return $a ? $a : 0;}sub undef_as_empty {    my $a = shift;    return $a ? $a : "";}{    my $hostname;    sub hostname {	if(not $hostname) {	    $hostname = `hostname`;	    chomp($hostname);	    $hostname ||= "nohostname";	}	return $hostname;    }}sub which {    # Input:    #   @programs = programs to find the path to    # Returns:    #   @full_path = full paths to @programs. Nothing if not found    my @which;    for my $prg (@_) {	push @which, map { $_."/".$prg } grep { -x $_."/".$prg } split(":",$ENV{'PATH'});    }    return @which;}{    my ($regexp,%fakename);    sub parent_shell {	# Input:	#   $pid = pid to see if (grand)*parent is a shell	# Returns:	#   $shellpath = path to shell - undef if no shell found	my $pid = shift;	if(not $regexp) {	    # All shells known to mankind	    #	    # ash bash csh dash fdsh fish fizsh ksh ksh93 mksh pdksh	    # posh rbash rush rzsh sash sh static-sh tcsh yash zsh	    my @shells = qw(ash bash csh dash fdsh fish fizsh ksh                            ksh93 mksh pdksh posh rbash rush rzsh                            sash sh static-sh tcsh yash zsh -sh -csh);	    # Can be formatted as:	    #   [sh]  -sh  sh  busybox sh	    #   /bin/sh /sbin/sh /opt/csw/sh	    # NOT: foo.sh sshd crash flush pdflush scosh fsflush ssh	    my $shell = "(?:".join("|",@shells).")";	    $regexp = '^((\[)('. $shell. ')(\])|(|\S+/|busybox )('. $shell. '))($| )';	    %fakename = (		# csh and tcsh disguise themselves as -sh/-csh		"-sh" => ["csh", "tcsh"],		"-csh" => ["tcsh", "csh"],		);	}	my ($children_of_ref, $parent_of_ref, $name_of_ref) = pid_table();	my $shellpath;	my $testpid = $pid;	while($testpid) {	    ::debug("init", "shell? ". $name_of_ref->{$testpid}."\n");	    if($name_of_ref->{$testpid} =~ /$regexp/o) {		::debug("init", "which ".($3||$6)." => ");		$shellpath = (which($3 || $6,@{$fakename{$3 || $6}}))[0];		::debug("init", "shell path $shellpath\n");		$shellpath and last;	    }	    $testpid = $parent_of_ref->{$testpid};	}	return $shellpath;    }}{    my %pid_parentpid_cmd;    sub pid_table {	# Returns:	#   %children_of = { pid -> children of pid }	#   %parent_of = { pid -> pid of parent }	#   %name_of = { pid -> commandname }       	if(not %pid_parentpid_cmd) {	    # Filter for SysV-style `ps`	    my $sysv = q( ps -ef | perl -ane '1..1 and /^(.*)CO?MM?A?N?D/ and $s=length $1;).		q(s/^.{$s}//; print "@F[1,2] $_"' );	    # BSD-style `ps`	    my $bsd = q(ps -o pid,ppid,command -ax);	    %pid_parentpid_cmd =	    (	     'aix' => $sysv,	     'cygwin' => $sysv,	     'msys' => $sysv,	     'dec_osf' => $sysv,	     'darwin' => $bsd,	     'dragonfly' => $bsd,	     'freebsd' => $bsd,	     'gnu' => $sysv,	     'hpux' => $sysv,	     'linux' => $sysv,	     'mirbsd' => $bsd,	     'netbsd' => $bsd,	     'nto' => $sysv,	     'openbsd' => $bsd,	     'solaris' => $sysv,	     'svr5' => $sysv,	    );	}	$pid_parentpid_cmd{$^O} or ::die_bug("pid_parentpid_cmd for $^O missing");	my (@pidtable,%parent_of,%children_of,%name_of);	# Table with pid -> children of pid	@pidtable = `$pid_parentpid_cmd{$^O}`;	my $p=$$;	for (@pidtable) {	    # must match: 24436 21224 busybox ash	    /(\S+)\s+(\S+)\s+(\S+.*)/ or ::die_bug("pidtable format: $_");	    $parent_of{$1} = $2;	    push @{$children_of{$2}}, $1;	    $name_of{$1} = $3;	}	return(\%children_of, \%parent_of, \%name_of);    }}sub reap_usleep {    # Reap dead children.    # If no dead children: Sleep specified amount with exponential backoff    # Input:    #   $ms = milliseconds to sleep    # Returns:    #   $ms/2+0.001 if children reaped    #   $ms*1.1 if no children reaped    my $ms = shift;    if(reaper()) {	# Sleep exponentially shorter (1/2^n) if a job finished	return $ms/2+0.001;    } else {	if($opt::timeout) {	    $Global::timeoutq->process_timeouts();	}	usleep($ms);	Job::exit_if_disk_full();	if($opt::linebuffer) {	    for my $job (values %Global::running) {		$job->print();	    }	}	# Sleep exponentially longer (1.1^n) if a job did not finish	# though at most 1000 ms.	return (($ms < 1000) ? ($ms * 1.1) : ($ms));    }}sub usleep {    # Sleep this many milliseconds.    # Input:    #   $ms = milliseconds to sleep    my $ms = shift;    ::debug(int($ms),"ms ");    select(undef, undef, undef, $ms/1000);}sub now {    # Returns time since epoch as in seconds with 3 decimals    # Uses:    #   @Global::use    # Returns:    #   $time = time now with millisecond accuracy    if(not $Global::use{"Time::HiRes"}) {	if(eval "use Time::HiRes qw ( time );") {	    eval "sub TimeHiRestime { return Time::HiRes::time };";	} else {	    eval "sub TimeHiRestime { return time() };";	}	$Global::use{"Time::HiRes"} = 1;    }    return (int(TimeHiRestime()*1000))/1000;}sub multiply_binary_prefix {    # Evalualte numbers with binary prefix    # Ki=2^10, Mi=2^20, Gi=2^30, Ti=2^40, Pi=2^50, Ei=2^70, Zi=2^80, Yi=2^80    # ki=2^10, mi=2^20, gi=2^30, ti=2^40, pi=2^50, ei=2^70, zi=2^80, yi=2^80    # K =2^10, M =2^20, G =2^30, T =2^40, P =2^50, E =2^70, Z =2^80, Y =2^80    # k =10^3, m =10^6, g =10^9, t=10^12, p=10^15, e=10^18, z=10^21, y=10^24    # 13G = 13*1024*1024*1024 = 13958643712    # Input:    #   $s = string with prefixes    # Returns:    #   $value = int with prefixes multiplied    my $s = shift;    $s =~ s/ki/*1024/gi;    $s =~ s/mi/*1024*1024/gi;    $s =~ s/gi/*1024*1024*1024/gi;    $s =~ s/ti/*1024*1024*1024*1024/gi;    $s =~ s/pi/*1024*1024*1024*1024*1024/gi;    $s =~ s/ei/*1024*1024*1024*1024*1024*1024/gi;    $s =~ s/zi/*1024*1024*1024*1024*1024*1024*1024/gi;    $s =~ s/yi/*1024*1024*1024*1024*1024*1024*1024*1024/gi;    $s =~ s/xi/*1024*1024*1024*1024*1024*1024*1024*1024*1024/gi;    $s =~ s/K/*1024/g;    $s =~ s/M/*1024*1024/g;    $s =~ s/G/*1024*1024*1024/g;    $s =~ s/T/*1024*1024*1024*1024/g;    $s =~ s/P/*1024*1024*1024*1024*1024/g;    $s =~ s/E/*1024*1024*1024*1024*1024*1024/g;    $s =~ s/Z/*1024*1024*1024*1024*1024*1024*1024/g;    $s =~ s/Y/*1024*1024*1024*1024*1024*1024*1024*1024/g;    $s =~ s/X/*1024*1024*1024*1024*1024*1024*1024*1024*1024/g;    $s =~ s/k/*1000/g;    $s =~ s/m/*1000*1000/g;    $s =~ s/g/*1000*1000*1000/g;    $s =~ s/t/*1000*1000*1000*1000/g;    $s =~ s/p/*1000*1000*1000*1000*1000/g;    $s =~ s/e/*1000*1000*1000*1000*1000*1000/g;    $s =~ s/z/*1000*1000*1000*1000*1000*1000*1000/g;    $s =~ s/y/*1000*1000*1000*1000*1000*1000*1000*1000/g;    $s =~ s/x/*1000*1000*1000*1000*1000*1000*1000*1000*1000/g;    $s = eval $s;    ::debug($s);    return $s;}sub tmpfile {    # Create tempfile as $TMPDIR/parXXXXX    # Returns:    #   $filename = file name created    return ::tempfile(DIR=>$ENV{'TMPDIR'}, TEMPLATE => 'parXXXXX', @_);}sub __DEBUGGING__ {}sub debug {    # Uses:    #   $Global::debug    #   %Global::fd    # Returns: N/A    $Global::debug or return;    @_ = grep { defined $_ ? $_ : "" } @_;    if($Global::debug eq "all" or $Global::debug eq $_[0]) {	if($Global::fd{1}) {	    # Original stdout was saved	    my $stdout = $Global::fd{1};	    print $stdout @_[1..$#_];	} else {	    print @_[1..$#_];	}    }}sub my_memory_usage {    # Returns:    #   memory usage if found    #   0 otherwise    use strict;    use FileHandle;    my $pid = $$;    if(-e "/proc/$pid/stat") {        my $fh = FileHandle->new("</proc/$pid/stat");        my $data = <$fh>;        chomp $data;        $fh->close;        my @procinfo = split(/\s+/,$data);        return undef_as_zero($procinfo[22]);    } else {        return 0;    }}sub my_size {    # Returns:    #   $size = size of object if Devel::Size is installed    #   -1 otherwise    my @size_this = (@_);    eval "use Devel::Size qw(size total_size)";    if ($@) {        return -1;    } else {        return total_size(@_);    }}sub my_dump {    # Returns:    #   ascii expression of object if Data::Dump(er) is installed    #   error code otherwise    my @dump_this = (@_);    eval "use Data::Dump qw(dump);";    if ($@) {        # Data::Dump not installed        eval "use Data::Dumper;";        if ($@) {            my $err =  "Neither Data::Dump nor Data::Dumper is installed\n".                "Not dumping output\n";            print $Global::original_stderr $err;            return $err;        } else {            return Dumper(@dump_this);        }    } else {	# Create a dummy Data::Dump:dump as Hans Schou sometimes has	# it undefined	eval "sub Data::Dump:dump {}";        eval "use Data::Dump qw(dump);";        return (Data::Dump::dump(@dump_this));    }}sub my_croak {    eval "use Carp; 1";    $Carp::Verbose = 1;    croak(@_);}sub my_carp {    eval "use Carp; 1";    $Carp::Verbose = 1;    carp(@_);}sub __OBJECT_ORIENTED_PARTS__ {}package SSHLogin;sub new {    my $class = shift;    my $sshlogin_string = shift;    my $ncpus;    my %hostgroups;    # SSHLogins can have these formats:    #   @grp+grp/ncpu//usr/bin/ssh user@server    #   ncpu//usr/bin/ssh user@server    #   /usr/bin/ssh user@server    #   user@server    #   ncpu/user@server    #   @grp+grp/user@server    if($sshlogin_string =~ s:^\@([^/]+)/?::) {        # Look for SSHLogin hostgroups        %hostgroups = map { $_ => 1 } split(/\+/, $1);    }    if ($sshlogin_string =~ s:^(\d+)/::) {        # Override default autodetected ncpus unless missing        $ncpus = $1;    }    my $string = $sshlogin_string;    # An SSHLogin is always in the hostgroup of its $string-name    $hostgroups{$string} = 1;    @Global::hostgroups{keys %hostgroups} = values %hostgroups;    my @unget = ();    my $no_slash_string = $string;    $no_slash_string =~ s/[^-a-z0-9:]/_/gi;    return bless {        'string' => $string,        'jobs_running' => 0,        'jobs_completed' => 0,        'maxlength' => undef,        'max_jobs_running' => undef,        'orig_max_jobs_running' => undef,        'ncpus' => $ncpus,        'hostgroups' => \%hostgroups,        'sshcommand' => undef,        'serverlogin' => undef,        'control_path_dir' => undef,        'control_path' => undef,	'time_to_login' => undef,	'last_login_at' => undef,        'loadavg_file' => $ENV{'HOME'} . "/.parallel/tmp/loadavg-" .            $no_slash_string,        'loadavg' => undef,	'last_loadavg_update' => 0,        'swap_activity_file' => $ENV{'HOME'} . "/.parallel/tmp/swap_activity-" .            $no_slash_string,        'swap_activity' => undef,    }, ref($class) || $class;}sub DESTROY {    my $self = shift;    # Remove temporary files if they are created.    unlink $self->{'loadavg_file'};    unlink $self->{'swap_activity_file'};}sub string {    my $self = shift;    return $self->{'string'};}sub jobs_running {    my $self = shift;    return ($self->{'jobs_running'} || "0");}sub inc_jobs_running {    my $self = shift;    $self->{'jobs_running'}++;}sub dec_jobs_running {    my $self = shift;    $self->{'jobs_running'}--;}sub set_maxlength {    my $self = shift;    $self->{'maxlength'} = shift;}sub maxlength {    my $self = shift;    return $self->{'maxlength'};}sub jobs_completed {    my $self = shift;    return $self->{'jobs_completed'};}sub in_hostgroups {    # Input:    #   @hostgroups = the hostgroups to look for    # Returns:    #   true if intersection of @hostgroups and the hostgroups of this    #        SSHLogin is non-empty    my $self = shift;    return grep { defined $self->{'hostgroups'}{$_} } @_;}sub hostgroups {    my $self = shift;    return keys %{$self->{'hostgroups'}};}sub inc_jobs_completed {    my $self = shift;    $self->{'jobs_completed'}++;}sub set_max_jobs_running {    my $self = shift;    if(defined $self->{'max_jobs_running'}) {        $Global::max_jobs_running -= $self->{'max_jobs_running'};    }    $self->{'max_jobs_running'} = shift;    if(defined $self->{'max_jobs_running'}) {        # max_jobs_running could be resat if -j is a changed file        $Global::max_jobs_running += $self->{'max_jobs_running'};    }    # Initialize orig to the first non-zero value that comes around    $self->{'orig_max_jobs_running'} ||= $self->{'max_jobs_running'};}sub swapping {    my $self = shift;    my $swapping = $self->swap_activity();    return (not defined $swapping or $swapping)}sub swap_activity {    # If the currently known swap activity is too old:    #   Recompute a new one in the background    # Returns:    #   last swap activity computed    my $self = shift;    # Should we update the swap_activity file?    my $update_swap_activity_file = 0;    if(-r $self->{'swap_activity_file'}) {        open(my $swap_fh, "<", $self->{'swap_activity_file'}) || ::die_bug("swap_activity_file-r");        my $swap_out = <$swap_fh>;        close $swap_fh;        if($swap_out =~ /^(\d+)$/) {            $self->{'swap_activity'} = $1;            ::debug("swap", "New swap_activity: ", $self->{'swap_activity'});        }        ::debug("swap", "Last update: ", $self->{'last_swap_activity_update'});        if(time - $self->{'last_swap_activity_update'} > 10) {            # last swap activity update was started 10 seconds ago            ::debug("swap", "Older than 10 sec: ", $self->{'swap_activity_file'});            $update_swap_activity_file = 1;        }    } else {        ::debug("swap", "No swap_activity file: ", $self->{'swap_activity_file'});        $self->{'swap_activity'} = undef;        $update_swap_activity_file = 1;    }    if($update_swap_activity_file) {        ::debug("swap", "Updating swap_activity file ", $self->{'swap_activity_file'});        $self->{'last_swap_activity_update'} = time;        -e $ENV{'HOME'}."/.parallel" or mkdir $ENV{'HOME'}."/.parallel";        -e $ENV{'HOME'}."/.parallel/tmp" or mkdir $ENV{'HOME'}."/.parallel/tmp";        my $swap_activity;	$swap_activity = swapactivityscript();        if($self->{'string'} ne ":") {            $swap_activity = $self->sshcommand() . " " . $self->serverlogin() . " " .		::shell_quote_scalar($swap_activity);        }        # Run swap_activity measuring.        # As the command can take long to run if run remote        # save it to a tmp file before moving it to the correct file        my $file = $self->{'swap_activity_file'};        my ($dummy_fh, $tmpfile) = ::tmpfile(SUFFIX => ".swp");	::debug("swap", "\n", $swap_activity, "\n");        qx{ ($swap_activity > $tmpfile && mv $tmpfile $file || rm $tmpfile) & };    }    return $self->{'swap_activity'};}{    my $script;    sub swapactivityscript {	# Returns:	#   shellscript for detecting swap activity	#	# arguments for vmstat are OS dependant	# swap_in and swap_out are in different columns depending on OS	#	if(not $script) {	    my %vmstat = (		# linux: $7*$8		# $ vmstat 1 2		# procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----		#  r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa		#  5  0  51208 1701096 198012 18857888    0    0    37   153   28   19 56 11 33  1		#  3  0  51208 1701288 198012 18857972    0    0     0     0 3638 10412 15  3 82  0		'linux' => ['vmstat 1 2 | tail -n1', '$7*$8'],		# solaris: $6*$7		# $ vmstat -S 1 2		#  kthr      memory            page            disk          faults      cpu		#  r b w   swap  free  si  so pi po fr de sr s3 s4 -- --   in   sy   cs us sy id		#  0 0 0 4628952 3208408 0  0  3  1  1  0  0 -0  2  0  0  263  613  246  1  2 97		#  0 0 0 4552504 3166360 0  0  0  0  0  0  0  0  0  0  0  246  213  240  1  1 98		'solaris' => ['vmstat -S 1 2 | tail -1', '$6*$7'],		# darwin (macosx): $21*$22		# $ vm_stat -c 2 1		# Mach Virtual Memory Statistics: (page size of 4096 bytes)		#     free   active   specul inactive throttle    wired  prgable   faults     copy    0fill reactive   purged file-backed anonymous cmprssed cmprssor  dcomprs   comprs  pageins  pageout  swapins swapouts		#   346306   829050    74871   606027        0   240231    90367  544858K 62343596  270837K    14178   415070      570102    939846      356      370      116      922  4019813        4        0        0		#   345740   830383    74875   606031        0   239234    90369     2696      359      553        0        0      570110    941179      356      370        0        0        0        0        0        0		'darwin' => ['vm_stat -c 2 1 | tail -n1', '$21*$22'],		# ultrix: $12*$13		# $ vmstat -S 1 2		#  procs      faults    cpu      memory              page             disk		#  r b w   in  sy  cs us sy id  avm  fre  si so  pi  po  fr  de  sr s0		#  1 0 0    4  23   2  3  0 97 7743 217k   0  0   0   0   0   0   0  0		#  1 0 0    6  40   8  0  1 99 7743 217k   0  0   3   0   0   0   0  0		'ultrix' => ['vmstat -S 1 2 | tail -1', '$12*$13'],		# aix: $6*$7		# $ vmstat 1 2		# System configuration: lcpu=1 mem=2048MB		#		# kthr    memory              page              faults        cpu		# ----- ----------- ------------------------ ------------ -----------		#  r  b   avm   fre  re  pi  po  fr   sr  cy  in   sy  cs us sy id wa		#  0  0 333933 241803   0   0   0   0    0   0  10  143  90  0  0 99  0		#  0  0 334125 241569   0   0   0   0    0   0  37 5368 184  0  9 86  5		'aix' => ['vmstat 1 2 | tail -n1', '$6*$7'],		# freebsd: $8*$9		# $ vmstat -H 1 2		#  procs      memory      page                    disks     faults         cpu		#  r b w     avm    fre   flt  re  pi  po    fr  sr ad0 ad1   in   sy   cs us sy id		#  1 0 0  596716   19560    32   0   0   0    33   8   0   0   11  220  277  0  0 99		#  0 0 0  596716   19560     2   0   0   0     0   0   0   0   11  144  263  0  1 99		'freebsd' => ['vmstat -H 1 2 | tail -n1', '$8*$9'],		# mirbsd: $8*$9		# $ vmstat 1 2		#  procs   memory        page                    disks     traps         cpu		#  r b w    avm    fre   flt  re  pi  po  fr  sr wd0 cd0  int   sys   cs us sy id		#  0 0 0  25776 164968    34   0   0   0   0   0   0   0  230   259   38  4  0 96		#  0 0 0  25776 164968    24   0   0   0   0   0   0   0  237   275   37  0  0 100		'mirbsd' => ['vmstat 1 2 | tail -n1', '$8*$9'],		# netbsd: $7*$8		# $ vmstat 1 2		#  procs    memory      page                       disks   faults      cpu		#  r b      avm    fre  flt  re  pi   po   fr   sr w0 w1   in   sy  cs us sy id		#  0 0   138452   6012   54   0   0    0    1    2  3  0    4  100  23  0  0 100		#  0 0   138456   6008    1   0   0    0    0    0  0  0    7   26  19  0 0 100		'netbsd' => ['vmstat 1 2 | tail -n1', '$7*$8'],		# openbsd: $8*$9		# $ vmstat 1 2		#  procs    memory       page                    disks    traps          cpu		#  r b w    avm     fre  flt  re  pi  po  fr  sr wd0 wd1  int   sys   cs us sy id		#  0 0 0  76596  109944   73   0   0   0   0   0   0   1    5   259   22  0  1 99		#  0 0 0  76604  109936   24   0   0   0   0   0   0   0    7   114   20  0  1 99		'openbsd' => ['vmstat 1 2 | tail -n1', '$8*$9'],		# hpux: $8*$9		# $ vmstat 1 2		#          procs           memory                   page                              faults       cpu		#     r     b     w      avm    free   re   at    pi   po    fr   de    sr     in     sy    cs  us sy id		#     1     0     0   247211  216476    4    1     0    0     0    0     0    102  73005    54   6 11 83		#     1     0     0   247211  216421   43    9     0    0     0    0     0    144   1675    96  25269512791222387000 25269512791222387000 105		'hpux' => ['vmstat 1 2 | tail -n1', '$8*$9'],		# dec_osf (tru64): $11*$12		# $ vmstat  1 2		# Virtual Memory Statistics: (pagesize = 8192)		#   procs      memory        pages                            intr       cpu		#   r   w   u  act free wire fault  cow zero react  pin pout  in  sy  cs us sy id		#   3 181  36  51K 1895 8696  348M  59M 122M   259  79M    0   5 218 302  4  1 94		#   3 181  36  51K 1893 8696     3   15   21     0   28    0   4  81 321  1  1 98		'dec_osf' => ['vmstat 1 2 | tail -n1', '$11*$12'],		# gnu (hurd): $7*$8		# $ vmstat -k 1 2		# (pagesize: 4, size: 512288, swap size: 894972)		#   free   actv  inact  wired   zeroed  react    pgins   pgouts  pfaults  cowpfs hrat    caobj  cache swfree		# 371940  30844  89228  20276   298348      0    48192    19016   756105   99808  98%      876  20628 894972		# 371940  30844  89228  20276       +0     +0       +0       +0      +42      +2  98%      876  20628 894972		'gnu' => ['vmstat -k 1 2 | tail -n1', '$7*$8'],		# -nto (qnx has no swap)		#-irix		#-svr5 (scosysv)		);	    my $perlscript = "";	    for my $os (keys %vmstat) {		#q[ { vmstat 1 2 2> /dev/null || vmstat -c 1 2; } | ].		#   q[ awk 'NR!=4{next} NF==17||NF==16{print $7*$8} NF==22{print $21*$22} {exit}' ];		$vmstat{$os}[1] =~ s/\$/\\\\\\\$/g; # $ => \\\$		$perlscript .= 'if($^O eq "'.$os.'") { print `'.$vmstat{$os}[0].' | awk "{print ' .		    $vmstat{$os}[1] . '}"` }';	    }	    $perlscript = "perl -e " . ::shell_quote_scalar($perlscript);	    $script = $Global::envvar. " " .$perlscript;	}	return $script;    }}sub too_fast_remote_login {    my $self = shift;    if($self->{'last_login_at'} and $self->{'time_to_login'}) {	# sshd normally allows 10 simultaneous logins	# A login takes time_to_login	# So time_to_login/5 should be safe	# If now <= last_login + time_to_login/5: Then it is too soon.	my $too_fast = (::now() <= $self->{'last_login_at'}			+ $self->{'time_to_login'}/5);	::debug("run", "Too fast? $too_fast ");	return $too_fast;    } else {	# No logins so far (or time_to_login not computed): it is not too fast	return 0;    }}sub last_login_at {    my $self = shift;    return $self->{'last_login_at'};}sub set_last_login_at {    my $self = shift;    $self->{'last_login_at'} = shift;}sub loadavg_too_high {    my $self = shift;    my $loadavg = $self->loadavg();    return (not defined $loadavg or            $loadavg > $self->max_loadavg());}sub loadavg {    # If the currently know loadavg is too old:    #   Recompute a new one in the background    # The load average is computed as the number of processes waiting for disk    # or CPU right now. So it is the server load this instant and not averaged over    # several minutes. This is needed so GNU Parallel will at most start one job    # that will push the load over the limit.    #    # Returns:    #   $last_loadavg = last load average computed (undef if none)    my $self = shift;    # Should we update the loadavg file?    my $update_loadavg_file = 0;    if(open(my $load_fh, "<", $self->{'loadavg_file'})) {	local $/ = undef;        my $load_out = <$load_fh>;        close $load_fh;	my $load =()= ($load_out=~/(^[DR]....[^\[])/gm);        if($load > 0) {	    # load is overestimated by 1            $self->{'loadavg'} = $load - 1;            ::debug("load", "New loadavg: ", $self->{'loadavg'});        } else {	    ::die_bug("loadavg_invalid_content: $load_out");	}        ::debug("load", "Last update: ", $self->{'last_loadavg_update'});        if(time - $self->{'last_loadavg_update'} > 10) {            # last loadavg was started 10 seconds ago            ::debug("load", time - $self->{'last_loadavg_update'}, " secs old: ",		    $self->{'loadavg_file'});            $update_loadavg_file = 1;        }    } else {        ::debug("load", "No loadavg file: ", $self->{'loadavg_file'});        $self->{'loadavg'} = undef;        $update_loadavg_file = 1;    }    if($update_loadavg_file) {        ::debug("load", "Updating loadavg file", $self->{'loadavg_file'}, "\n");        $self->{'last_loadavg_update'} = time;        -e $ENV{'HOME'}."/.parallel" or mkdir $ENV{'HOME'}."/.parallel";        -e $ENV{'HOME'}."/.parallel/tmp" or mkdir $ENV{'HOME'}."/.parallel/tmp";        my $cmd = "";        if($self->{'string'} ne ":") {	    $cmd = $self->sshcommand() . " " . $self->serverlogin() . " ";	}	# TODO Is is called 'ps ax -o state,command' on other platforms?	$cmd .= "ps ax -o state,command";        # As the command can take long to run if run remote        # save it to a tmp file before moving it to the correct file        my $file = $self->{'loadavg_file'};        my ($dummy_fh, $tmpfile) = ::tmpfile(SUFFIX => ".loa");        qx{ ($cmd > $tmpfile && mv $tmpfile $file || rm $tmpfile) & };    }    return $self->{'loadavg'};}sub max_loadavg {    my $self = shift;    # If --load is a file it might be changed    if($Global::max_load_file) {	my $mtime = (stat($Global::max_load_file))[9];	if($mtime > $Global::max_load_file_last_mod) {	    $Global::max_load_file_last_mod = $mtime;	    for my $sshlogin (values %Global::host) {		$sshlogin->set_max_loadavg(undef);	    }	}    }    if(not defined $self->{'max_loadavg'}) {        $self->{'max_loadavg'} =            $self->compute_max_loadavg($opt::load);    }    ::debug("load", "max_loadavg: ", $self->string(), " ", $self->{'max_loadavg'});    return $self->{'max_loadavg'};}sub set_max_loadavg {    my $self = shift;    $self->{'max_loadavg'} = shift;}sub compute_max_loadavg {    # Parse the max loadaverage that the user asked for using --load    # Returns:    #   max loadaverage    my $self = shift;    my $loadspec = shift;    my $load;    if(defined $loadspec) {        if($loadspec =~ /^\+(\d+)$/) {            # E.g. --load +2            my $j = $1;            $load =                $self->ncpus() + $j;        } elsif ($loadspec =~ /^-(\d+)$/) {            # E.g. --load -2            my $j = $1;            $load =                $self->ncpus() - $j;        } elsif ($loadspec =~ /^(\d+)\%$/) {            my $j = $1;            $load =                $self->ncpus() * $j / 100;        } elsif ($loadspec =~ /^(\d+(\.\d+)?)$/) {            $load = $1;        } elsif (-f $loadspec) {            $Global::max_load_file = $loadspec;            $Global::max_load_file_last_mod = (stat($Global::max_load_file))[9];            if(open(my $in_fh, "<", $Global::max_load_file)) {                my $opt_load_file = join("",<$in_fh>);                close $in_fh;                $load = $self->compute_max_loadavg($opt_load_file);            } else {                print $Global::original_stderr "Cannot open $loadspec\n";                ::wait_and_exit(255);            }        } else {            print $Global::original_stderr "Parsing of --load failed\n";            ::die_usage();        }        if($load < 0.01) {            $load = 0.01;        }    }    return $load;}sub time_to_login {    my $self = shift;    return $self->{'time_to_login'};}sub set_time_to_login {    my $self = shift;    $self->{'time_to_login'} = shift;}sub max_jobs_running {    my $self = shift;    if(not defined $self->{'max_jobs_running'}) {        my $nproc = $self->compute_number_of_processes($opt::jobs);        $self->set_max_jobs_running($nproc);    }    return $self->{'max_jobs_running'};}sub orig_max_jobs_running {    my $self = shift;    return $self->{'orig_max_jobs_running'};}sub compute_number_of_processes {    # Number of processes wanted and limited by system resources    # Returns:    #   Number of processes    my $self = shift;    my $opt_P = shift;    my $wanted_processes = $self->user_requested_processes($opt_P);    if(not defined $wanted_processes) {        $wanted_processes = $Global::default_simultaneous_sshlogins;    }    ::debug("load", "Wanted procs: $wanted_processes\n");    my $system_limit =        $self->processes_available_by_system_limit($wanted_processes);    ::debug("load", "Limited to procs: $system_limit\n");    return $system_limit;}sub processes_available_by_system_limit {    # If the wanted number of processes is bigger than the system limits:    # Limit them to the system limits    # Limits are: File handles, number of input lines, processes,    # and taking > 1 second to spawn 10 extra processes    # Returns:    #   Number of processes    my $self = shift;    my $wanted_processes = shift;    my $system_limit = 0;    my @jobs = ();    my $job;    my @args = ();    my $arg;    my $more_filehandles = 1;    my $max_system_proc_reached = 0;    my $slow_spawining_warning_printed = 0;    my $time = time;    my %fh;    my @children;    # Reserve filehandles    # perl uses 7 filehandles for something?    # parallel uses 1 for memory_usage    # parallel uses 4 for ?    for my $i (1..12) {        open($fh{"init-$i"}, "<", "/dev/null");    }    for(1..2) {        # System process limit        my $child;        if($child = fork()) {            push (@children,$child);            $Global::unkilled_children{$child} = 1;        } elsif(defined $child) {            # The child takes one process slot            # It will be killed later            $SIG{TERM} = $Global::original_sig{TERM};            sleep 10000000;            exit(0);        } else {            $max_system_proc_reached = 1;        }    }    my $count_jobs_already_read = $Global::JobQueue->next_seq();    my $wait_time_for_getting_args = 0;    my $start_time = time;    while(1) {        $system_limit >= $wanted_processes and last;        not $more_filehandles and last;        $max_system_proc_reached and last;	my $before_getting_arg = time;        if($Global::semaphore or $opt::pipe) {	    # Skip: No need to get args        } elsif(defined $opt::retries and $count_jobs_already_read) {            # For retries we may need to run all jobs on this sshlogin            # so include the already read jobs for this sshlogin            $count_jobs_already_read--;        } else {            if($opt::X or $opt::m) {                # The arguments may have to be re-spread over several jobslots                # So pessimistically only read one arg per jobslot                # instead of a full commandline                if($Global::JobQueue->{'commandlinequeue'}->{'arg_queue'}->empty()) {		    if($Global::JobQueue->empty()) {			last;		    } else {			($job) = $Global::JobQueue->get();			push(@jobs, $job);		    }		} else {		    ($arg) = $Global::JobQueue->{'commandlinequeue'}->{'arg_queue'}->get();		    push(@args, $arg);		}            } else {                # If there are no more command lines, then we have a process                # per command line, so no need to go further                $Global::JobQueue->empty() and last;                ($job) = $Global::JobQueue->get();                push(@jobs, $job);	    }        }	$wait_time_for_getting_args += time - $before_getting_arg;        $system_limit++;        # Every simultaneous process uses 2 filehandles when grouping        # Every simultaneous process uses 2 filehandles when compressing        $more_filehandles = open($fh{$system_limit*10}, "<", "/dev/null")            && open($fh{$system_limit*10+2}, "<", "/dev/null")            && open($fh{$system_limit*10+3}, "<", "/dev/null")            && open($fh{$system_limit*10+4}, "<", "/dev/null");        # System process limit        my $child;        if($child = fork()) {            push (@children,$child);            $Global::unkilled_children{$child} = 1;        } elsif(defined $child) {            # The child takes one process slot            # It will be killed later            $SIG{TERM} = $Global::original_sig{TERM};            sleep 10000000;            exit(0);        } else {            $max_system_proc_reached = 1;        }	my $forktime = time - $time - $wait_time_for_getting_args;        ::debug("run", "Time to fork $system_limit procs: $wait_time_for_getting_args ",		$forktime,		" (processes so far: ", $system_limit,")\n");        if($system_limit > 10 and	   $forktime > 1 and	   $forktime > $system_limit * 0.01	   and not $slow_spawining_warning_printed) {            # It took more than 0.01 second to fork a processes on avg.            # Give the user a warning. He can press Ctrl-C if this            # sucks.            print $Global::original_stderr                ("parallel: Warning: Starting $system_limit processes took > $forktime sec.\n",                 "Consider adjusting -j. Press CTRL-C to stop.\n");            $slow_spawining_warning_printed = 1;        }    }    # Cleanup: Close the files    for (values %fh) { close $_ }    # Cleanup: Kill the children    for my $pid (@children) {        kill 9, $pid;        waitpid($pid,0);        delete $Global::unkilled_children{$pid};    }    # Cleanup: Unget the command_lines or the @args    $Global::JobQueue->{'commandlinequeue'}->{'arg_queue'}->unget(@args);    $Global::JobQueue->unget(@jobs);    if($system_limit < $wanted_processes) {	# The system_limit is less than the wanted_processes	if($system_limit < 1 and not $Global::JobQueue->empty()) {	    ::warning("Cannot spawn any jobs. Raising ulimit -u or /etc/security/limits.conf\n",		      "or /proc/sys/kernel/pid_max may help.\n");	    ::wait_and_exit(255);	}	if(not $more_filehandles) {	    ::warning("Only enough file handles to run ", $system_limit, " jobs in parallel.\n",		      "Running 'parallel -j0 -N", $system_limit, " --pipe parallel -j0' or ",		      "raising ulimit -n or /etc/security/limits.conf may help.\n");	}	if($max_system_proc_reached) {	    ::warning("Only enough available processes to run ", $system_limit,		      " jobs in parallel. Raising ulimit -u or /etc/security/limits.conf\n",		      "or /proc/sys/kernel/pid_max may help.\n");	}    }    if($] == 5.008008 and $system_limit > 1000) {	# https://savannah.gnu.org/bugs/?36942	$system_limit = 1000;    }    if($Global::JobQueue->empty()) {	$system_limit ||= 1;    }    if($self->string() ne ":" and       $system_limit > $Global::default_simultaneous_sshlogins) {        $system_limit =            $self->simultaneous_sshlogin_limit($system_limit);    }    return $system_limit;}sub simultaneous_sshlogin_limit {    # Test by logging in wanted number of times simultaneously    # Returns:    #   min($wanted_processes,$working_simultaneous_ssh_logins-1)    my $self = shift;    my $wanted_processes = shift;    if($self->{'time_to_login'}) {	return $wanted_processes;    }    # Try twice because it guesses wrong sometimes    # Choose the minimal    my $ssh_limit =        ::min($self->simultaneous_sshlogin($wanted_processes),	      $self->simultaneous_sshlogin($wanted_processes));    if($ssh_limit < $wanted_processes) {        my $serverlogin = $self->serverlogin();        ::warning("ssh to $serverlogin only allows ",		  "for $ssh_limit simultaneous logins.\n",		  "You may raise this by changing ",		  "/etc/ssh/sshd_config:MaxStartups and MaxSessions on $serverlogin.\n",		  "Using only ",$ssh_limit-1," connections ",		  "to avoid race conditions.\n");    }    # Race condition can cause problem if using all sshs.    if($ssh_limit > 1) { $ssh_limit -= 1; }    return $ssh_limit;}sub simultaneous_sshlogin {    # Using $sshlogin try to see if we can do $wanted_processes    # simultaneous logins    # (ssh host echo simultaneouslogin & ssh host echo simultaneouslogin & ...)|grep simul|wc -l    # Returns:    #   Number of succesful logins    my $self = shift;    my $wanted_processes = shift;    my $sshcmd = $self->sshcommand();    my $serverlogin = $self->serverlogin();    my $sshdelay = $opt::sshdelay ? "sleep $opt::sshdelay;" : "";    my $cmd = "$sshdelay$sshcmd $serverlogin echo simultaneouslogin </dev/null 2>&1 &"x$wanted_processes;    ::debug("init", "Trying $wanted_processes logins at $serverlogin\n");    open (my $simul_fh, "-|", "($cmd)|grep simultaneouslogin | wc -l") or	::die_bug("simultaneouslogin");    my $ssh_limit = <$simul_fh>;    close $simul_fh;    chomp $ssh_limit;    return $ssh_limit;}sub set_ncpus {    my $self = shift;    $self->{'ncpus'} = shift;}sub user_requested_processes {    # Parse the number of processes that the user asked for using -j    # Returns:    #   the number of processes to run on this sshlogin    my $self = shift;    my $opt_P = shift;    my $processes;    if(defined $opt_P) {        if($opt_P =~ /^\+(\d+)$/) {            # E.g. -P +2            my $j = $1;            $processes =                $self->ncpus() + $j;        } elsif ($opt_P =~ /^-(\d+)$/) {            # E.g. -P -2            my $j = $1;            $processes =                $self->ncpus() - $j;        } elsif ($opt_P =~ /^(\d+(\.\d+)?)\%$/) {            # E.g. -P 10.5%            my $j = $1;            $processes =                $self->ncpus() * $j / 100;        } elsif ($opt_P =~ /^(\d+)$/) {            $processes = $1;            if($processes == 0) {                # -P 0 = infinity (or at least close)                $processes = $Global::infinity;            }        } elsif (-f $opt_P) {            $Global::max_procs_file = $opt_P;            $Global::max_procs_file_last_mod = (stat($Global::max_procs_file))[9];            if(open(my $in_fh, "<", $Global::max_procs_file)) {                my $opt_P_file = join("",<$in_fh>);                close $in_fh;                $processes = $self->user_requested_processes($opt_P_file);            } else {                ::error("Cannot open $opt_P.\n");                ::wait_and_exit(255);            }        } else {            ::error("Parsing of --jobs/-j/--max-procs/-P failed.\n");            ::die_usage();        }	$processes = ::ceil($processes);    }    return $processes;}sub ncpus {    my $self = shift;    if(not defined $self->{'ncpus'}) {        my $sshcmd = $self->sshcommand();        my $serverlogin = $self->serverlogin();        if($serverlogin eq ":") {            if($opt::use_cpus_instead_of_cores) {                $self->{'ncpus'} = no_of_cpus();            } else {                $self->{'ncpus'} = no_of_cores();            }        } else {            my $ncpu;	    my $sqe = ::shell_quote_scalar($Global::envvar);            if($opt::use_cpus_instead_of_cores) {                $ncpu = qx(echo|$sshcmd $serverlogin $sqe parallel --number-of-cpus);            } else {		::debug("init",qq(echo|$sshcmd $serverlogin $sqe parallel --number-of-cores\n));                $ncpu = qx(echo|$sshcmd $serverlogin $sqe parallel --number-of-cores);            }	    chomp $ncpu;            if($ncpu =~ /^\s*[0-9]+\s*$/s) {                $self->{'ncpus'} = $ncpu;            } else {                ::warning("Could not figure out ",			  "number of cpus on $serverlogin ($ncpu). Using 1.\n");                $self->{'ncpus'} = 1;            }        }    }    return $self->{'ncpus'};}sub no_of_cpus {    # Returns:    #   Number of physical CPUs    local $/="\n"; # If delimiter is set, then $/ will be wrong    my $no_of_cpus;    if ($^O eq 'linux') {        $no_of_cpus = no_of_cpus_gnu_linux() || no_of_cores_gnu_linux();    } elsif ($^O eq 'freebsd') {        $no_of_cpus = no_of_cpus_freebsd();    } elsif ($^O eq 'netbsd') {        $no_of_cpus = no_of_cpus_netbsd();    } elsif ($^O eq 'openbsd') {        $no_of_cpus = no_of_cpus_openbsd();    } elsif ($^O eq 'gnu') {        $no_of_cpus = no_of_cpus_hurd();    } elsif ($^O eq 'darwin') {	$no_of_cpus = no_of_cpus_darwin();    } elsif ($^O eq 'solaris') {        $no_of_cpus = no_of_cpus_solaris();    } elsif ($^O eq 'aix') {        $no_of_cpus = no_of_cpus_aix();    } elsif ($^O eq 'hpux') {        $no_of_cpus = no_of_cpus_hpux();    } elsif ($^O eq 'nto') {        $no_of_cpus = no_of_cpus_qnx();    } elsif ($^O eq 'svr5') {        $no_of_cpus = no_of_cpus_openserver();    } elsif ($^O eq 'irix') {        $no_of_cpus = no_of_cpus_irix();    } elsif ($^O eq 'dec_osf') {        $no_of_cpus = no_of_cpus_tru64();    } else {	$no_of_cpus = (no_of_cpus_gnu_linux()		       || no_of_cpus_freebsd()		       || no_of_cpus_netbsd()		       || no_of_cpus_openbsd()		       || no_of_cpus_hurd()		       || no_of_cpus_darwin()		       || no_of_cpus_solaris()		       || no_of_cpus_aix()		       || no_of_cpus_hpux()		       || no_of_cpus_qnx()		       || no_of_cpus_openserver()		       || no_of_cpus_irix()		       || no_of_cpus_tru64()			# Number of cores is better than no guess for #CPUs		       || nproc()	    );    }    if($no_of_cpus) {	chomp $no_of_cpus;        return $no_of_cpus;    } else {        ::warning("Cannot figure out number of cpus. Using 1.\n");        return 1;    }}sub no_of_cores {    # Returns:    #   Number of CPU cores    local $/="\n"; # If delimiter is set, then $/ will be wrong    my $no_of_cores;    if ($^O eq 'linux') {	$no_of_cores = no_of_cores_gnu_linux();    } elsif ($^O eq 'freebsd') {        $no_of_cores = no_of_cores_freebsd();    } elsif ($^O eq 'netbsd') {        $no_of_cores = no_of_cores_netbsd();    } elsif ($^O eq 'openbsd') {        $no_of_cores = no_of_cores_openbsd();    } elsif ($^O eq 'gnu') {        $no_of_cores = no_of_cores_hurd();    } elsif ($^O eq 'darwin') {	$no_of_cores = no_of_cores_darwin();    } elsif ($^O eq 'solaris') {	$no_of_cores = no_of_cores_solaris();    } elsif ($^O eq 'aix') {        $no_of_cores = no_of_cores_aix();    } elsif ($^O eq 'hpux') {        $no_of_cores = no_of_cores_hpux();    } elsif ($^O eq 'nto') {        $no_of_cores = no_of_cores_qnx();    } elsif ($^O eq 'svr5') {        $no_of_cores = no_of_cores_openserver();    } elsif ($^O eq 'irix') {        $no_of_cores = no_of_cores_irix();    } elsif ($^O eq 'dec_osf') {        $no_of_cores = no_of_cores_tru64();    } else {	$no_of_cores = (no_of_cores_gnu_linux()			|| no_of_cores_freebsd()			|| no_of_cores_netbsd()			|| no_of_cores_openbsd()			|| no_of_cores_hurd()			|| no_of_cores_darwin()			|| no_of_cores_solaris()			|| no_of_cores_aix()			|| no_of_cores_hpux()			|| no_of_cores_qnx()			|| no_of_cores_openserver()			|| no_of_cores_irix()			|| no_of_cores_tru64()			|| nproc()	    );    }    if($no_of_cores) {	chomp $no_of_cores;        return $no_of_cores;    } else {        ::warning("Cannot figure out number of CPU cores. Using 1.\n");        return 1;    }}sub nproc {    # Returns:    #   Number of cores using `nproc`    my $no_of_cores = `nproc 2>/dev/null`;    return $no_of_cores;}sub no_of_cpus_gnu_linux {    # Returns:    #   Number of physical CPUs on GNU/Linux    #   undef if not GNU/Linux    my $no_of_cpus;    my $no_of_cores;    if(-e "/proc/cpuinfo") {        $no_of_cpus = 0;        $no_of_cores = 0;        my %seen;        open(my $in_fh, "<", "/proc/cpuinfo") || return undef;        while(<$in_fh>) {            if(/^physical id.*[:](.*)/ and not $seen{$1}++) {                $no_of_cpus++;            }            /^processor.*[:]/i and $no_of_cores++;        }        close $in_fh;    }    return ($no_of_cpus||$no_of_cores);}sub no_of_cores_gnu_linux {    # Returns:    #   Number of CPU cores on GNU/Linux    #   undef if not GNU/Linux    my $no_of_cores;    if(-e "/proc/cpuinfo") {        $no_of_cores = 0;        open(my $in_fh, "<", "/proc/cpuinfo") || return undef;        while(<$in_fh>) {            /^processor.*[:]/i and $no_of_cores++;        }        close $in_fh;    }    return $no_of_cores;}sub no_of_cpus_freebsd {    # Returns:    #   Number of physical CPUs on FreeBSD    #   undef if not FreeBSD    my $no_of_cpus =	(`sysctl -a dev.cpu 2>/dev/null | grep \%parent | awk '{ print \$2 }' | uniq | wc -l | awk '{ print \$1 }'`	 or	 `sysctl hw.ncpu 2>/dev/null | awk '{ print \$2 }'`);    chomp $no_of_cpus;    return $no_of_cpus;}sub no_of_cores_freebsd {    # Returns:    #   Number of CPU cores on FreeBSD    #   undef if not FreeBSD    my $no_of_cores =	(`sysctl hw.ncpu 2>/dev/null | awk '{ print \$2 }'`	 or	 `sysctl -a hw  2>/dev/null | grep [^a-z]logicalcpu[^a-z] | awk '{ print \$2 }'`);    chomp $no_of_cores;    return $no_of_cores;}sub no_of_cpus_netbsd {    # Returns:    #   Number of physical CPUs on NetBSD    #   undef if not NetBSD    my $no_of_cpus = `sysctl -n hw.ncpu 2>/dev/null`;    chomp $no_of_cpus;    return $no_of_cpus;}sub no_of_cores_netbsd {    # Returns:    #   Number of CPU cores on NetBSD    #   undef if not NetBSD    my $no_of_cores = `sysctl -n hw.ncpu 2>/dev/null`;    chomp $no_of_cores;    return $no_of_cores;}sub no_of_cpus_openbsd {    # Returns:    #   Number of physical CPUs on OpenBSD    #   undef if not OpenBSD    my $no_of_cpus = `sysctl -n hw.ncpu 2>/dev/null`;    chomp $no_of_cpus;    return $no_of_cpus;}sub no_of_cores_openbsd {    # Returns:    #   Number of CPU cores on OpenBSD    #   undef if not OpenBSD    my $no_of_cores = `sysctl -n hw.ncpu 2>/dev/null`;    chomp $no_of_cores;    return $no_of_cores;}sub no_of_cpus_hurd {    # Returns:    #   Number of physical CPUs on HURD    #   undef if not HURD    my $no_of_cpus = `nproc`;    chomp $no_of_cpus;    return $no_of_cpus;}sub no_of_cores_hurd {    # Returns:    #   Number of physical CPUs on HURD    #   undef if not HURD    my $no_of_cores = `nproc`;    chomp $no_of_cores;    return $no_of_cores;}sub no_of_cpus_darwin {    # Returns:    #   Number of physical CPUs on Mac Darwin    #   undef if not Mac Darwin    my $no_of_cpus =	(`sysctl -n hw.physicalcpu 2>/dev/null`	 or	 `sysctl -a hw 2>/dev/null | grep [^a-z]physicalcpu[^a-z] | awk '{ print \$2 }'`);    return $no_of_cpus;}sub no_of_cores_darwin {    # Returns:    #   Number of CPU cores on Mac Darwin    #   undef if not Mac Darwin    my $no_of_cores =	(`sysctl -n hw.logicalcpu 2>/dev/null`	 or	 `sysctl -a hw  2>/dev/null | grep [^a-z]logicalcpu[^a-z] | awk '{ print \$2 }'`);    return $no_of_cores;}sub no_of_cpus_solaris {    # Returns:    #   Number of physical CPUs on Solaris    #   undef if not Solaris    if(-x "/usr/sbin/psrinfo") {        my @psrinfo = `/usr/sbin/psrinfo`;        if($#psrinfo >= 0) {            return $#psrinfo +1;        }    }    if(-x "/usr/sbin/prtconf") {        my @prtconf = `/usr/sbin/prtconf | grep cpu..instance`;        if($#prtconf >= 0) {            return $#prtconf +1;        }    }    return undef;}sub no_of_cores_solaris {    # Returns:    #   Number of CPU cores on Solaris    #   undef if not Solaris    if(-x "/usr/sbin/psrinfo") {        my @psrinfo = `/usr/sbin/psrinfo`;        if($#psrinfo >= 0) {            return $#psrinfo +1;        }    }    if(-x "/usr/sbin/prtconf") {        my @prtconf = `/usr/sbin/prtconf | grep cpu..instance`;        if($#prtconf >= 0) {            return $#prtconf +1;        }    }    return undef;}sub no_of_cpus_aix {    # Returns:    #   Number of physical CPUs on AIX    #   undef if not AIX    my $no_of_cpus = 0;    if(-x "/usr/sbin/lscfg") {	open(my $in_fh, "-|", "/usr/sbin/lscfg -vs |grep proc | wc -l|tr -d ' '")	    || return undef;	$no_of_cpus = <$in_fh>;	chomp ($no_of_cpus);	close $in_fh;    }    return $no_of_cpus;}sub no_of_cores_aix {    # Returns:    #   Number of CPU cores on AIX    #   undef if not AIX    my $no_of_cores;    if(-x "/usr/bin/vmstat") {	open(my $in_fh, "-|", "/usr/bin/vmstat 1 1") || return undef;	while(<$in_fh>) {	    /lcpu=([0-9]*) / and $no_of_cores = $1;	}	close $in_fh;    }    return $no_of_cores;}sub no_of_cpus_hpux {    # Returns:    #   Number of physical CPUs on HP-UX    #   undef if not HP-UX    my $no_of_cpus =        (`/usr/bin/mpsched -s 2>&1 | grep 'Locality Domain Count' | awk '{ print \$4 }'`);    return $no_of_cpus;}sub no_of_cores_hpux {    # Returns:    #   Number of CPU cores on HP-UX    #   undef if not HP-UX    my $no_of_cores =        (`/usr/bin/mpsched -s 2>&1 | grep 'Processor Count' | awk '{ print \$3 }'`);    return $no_of_cores;}sub no_of_cpus_qnx {    # Returns:    #   Number of physical CPUs on QNX    #   undef if not QNX    # BUG: It is now known how to calculate this.    my $no_of_cpus = 0;    return $no_of_cpus;}sub no_of_cores_qnx {    # Returns:    #   Number of CPU cores on QNX    #   undef if not QNX    # BUG: It is now known how to calculate this.    my $no_of_cores = 0;    return $no_of_cores;}sub no_of_cpus_openserver {    # Returns:    #   Number of physical CPUs on SCO OpenServer    #   undef if not SCO OpenServer    my $no_of_cpus = 0;    if(-x "/usr/sbin/psrinfo") {        my @psrinfo = `/usr/sbin/psrinfo`;        if($#psrinfo >= 0) {            return $#psrinfo +1;        }    }    return $no_of_cpus;}sub no_of_cores_openserver {    # Returns:    #   Number of CPU cores on SCO OpenServer    #   undef if not SCO OpenServer    my $no_of_cores = 0;    if(-x "/usr/sbin/psrinfo") {        my @psrinfo = `/usr/sbin/psrinfo`;        if($#psrinfo >= 0) {            return $#psrinfo +1;        }    }    return $no_of_cores;}sub no_of_cpus_irix {    # Returns:    #   Number of physical CPUs on IRIX    #   undef if not IRIX    my $no_of_cpus = `hinv | grep HZ | grep Processor | awk '{print \$1}'`;    return $no_of_cpus;}sub no_of_cores_irix {    # Returns:    #   Number of CPU cores on IRIX    #   undef if not IRIX    my $no_of_cores = `hinv | grep HZ | grep Processor | awk '{print \$1}'`;    return $no_of_cores;}sub no_of_cpus_tru64 {    # Returns:    #   Number of physical CPUs on Tru64    #   undef if not Tru64    my $no_of_cpus = `sizer -pr`;    return $no_of_cpus;}sub no_of_cores_tru64 {    # Returns:    #   Number of CPU cores on Tru64    #   undef if not Tru64    my $no_of_cores = `sizer -pr`;    return $no_of_cores;}sub sshcommand {    my $self = shift;    if (not defined $self->{'sshcommand'}) {        $self->sshcommand_of_sshlogin();    }    return $self->{'sshcommand'};}sub serverlogin {    my $self = shift;    if (not defined $self->{'serverlogin'}) {        $self->sshcommand_of_sshlogin();    }    return $self->{'serverlogin'};}sub sshcommand_of_sshlogin {    # 'server' -> ('ssh -S /tmp/parallel-ssh-RANDOM/host-','server')    # 'user@server' -> ('ssh','user@server')    # 'myssh user@server' -> ('myssh','user@server')    # 'myssh -l user server' -> ('myssh -l user','server')    # '/usr/bin/myssh -l user server' -> ('/usr/bin/myssh -l user','server')    # Returns:    #   sshcommand - defaults to 'ssh'    #   login@host    my $self = shift;    my ($sshcmd, $serverlogin);    if($self->{'string'} =~ /(.+) (\S+)$/) {        # Own ssh command        $sshcmd = $1; $serverlogin = $2;    } else {        # Normal ssh        if($opt::controlmaster) {            # Use control_path to make ssh faster            my $control_path = $self->control_path_dir()."/ssh-%r@%h:%p";            $sshcmd = "ssh -S ".$control_path;            $serverlogin = $self->{'string'};            if(not $self->{'control_path'}{$control_path}++) {                # Master is not running for this control_path                # Start it                my $pid = fork();                if($pid) {                    $Global::sshmaster{$pid} ||= 1;                } else {		    $SIG{'TERM'} = undef;                    # Ignore the 'foo' being printed                    open(STDOUT,">","/dev/null");                    # OpenSSH_3.6.1p2 gives 'tcgetattr: Invalid argument' with -tt                    # STDERR >/dev/null to ignore "process_mux_new_session: tcgetattr: Invalid argument"                    open(STDERR,">","/dev/null");                    open(STDIN,"<","/dev/null");                    # Run a sleep that outputs data, so it will discover if the ssh connection closes.                    my $sleep = ::shell_quote_scalar('$|=1;while(1){sleep 1;print "foo\n"}');                    my @master = ("ssh", "-tt", "-MTS", $control_path, $serverlogin, "perl", "-e", $sleep);                    exec(@master);                }            }        } else {            $sshcmd = "ssh"; $serverlogin = $self->{'string'};        }    }    $self->{'sshcommand'} = $sshcmd;    $self->{'serverlogin'} = $serverlogin;}sub control_path_dir {    # Returns:    #   path to directory    my $self = shift;    if(not defined $self->{'control_path_dir'}) {        -e $ENV{'HOME'}."/.parallel" or mkdir $ENV{'HOME'}."/.parallel";        -e $ENV{'HOME'}."/.parallel/tmp" or mkdir $ENV{'HOME'}."/.parallel/tmp";        $self->{'control_path_dir'} =	    File::Temp::tempdir($ENV{'HOME'}				. "/.parallel/tmp/control_path_dir-XXXX",				CLEANUP => 1);    }    return $self->{'control_path_dir'};}sub rsync_transfer_cmd {    # Command to run to transfer a file    # Input:    #   $file = filename of file to transfer    #   $workdir = destination dir    # Returns:    #   $cmd = rsync command to run to transfer $file ("" if unreadable)    my $self = shift;    my $file = shift;    my $workdir = shift;    if(not -r $file) {	::warning($file, " is not readable and will not be transferred.\n");	return "true";    }    my $rsync_destdir;    if($file =~ m:^/:) {	# rsync /foo/bar /	$rsync_destdir = "/";    } else {	$rsync_destdir = ::shell_quote_file($workdir);    }    $file = ::shell_quote_file($file);    my $sshcmd = $self->sshcommand();    my $rsync_opt = "-rlDzR -e" . ::shell_quote_scalar($sshcmd);    my $serverlogin = $self->serverlogin();    # Make dir if it does not exist    return "( $sshcmd $serverlogin mkdir -p $rsync_destdir;" .	rsync()." $rsync_opt $file $serverlogin:$rsync_destdir )";}sub cleanup_cmd {    # Command to run to remove the remote file    # Input:    #   $file = filename to remove    #   $workdir = destination dir    # Returns:    #   $cmd = ssh command to run to remove $file and empty parent dirs    my $self = shift;    my $file = shift;    my $workdir = shift;    my $f = $file;    if($f =~ m:/\./:) {	# foo/bar/./baz/quux => workdir/baz/quux	# /foo/bar/./baz/quux => workdir/baz/quux	$f =~ s:.*/\./:$workdir/:;    } elsif($f =~ m:^[^/]:) {	# foo/bar => workdir/foo/bar	$f = $workdir."/".$f;    }    my @subdirs = split m:/:, ::dirname($f);    my @rmdir;    my $dir = "";    for(@subdirs) {	$dir .= $_."/";	unshift @rmdir, ::shell_quote_file($dir);    }    my $rmdir = @rmdir ? "rmdir @rmdir 2>/dev/null;" : "";    if(defined $opt::workdir and $opt::workdir eq "...") {	$rmdir .= "rm -rf " . ::shell_quote_file($workdir).';';    }    $f = ::shell_quote_file($f);    my $sshcmd = $self->sshcommand();    my $serverlogin = $self->serverlogin();    return "$sshcmd $serverlogin ".::shell_quote_scalar("(rm -f $f; $rmdir)");}{    my $rsync;    sub rsync {	# rsync 3.1.x uses protocol 31 which is unsupported by 2.5.7.	# If the version >= 3.1.0: downgrade to protocol 30	if(not $rsync) {	    my @out = `rsync --version`;	    for (@out) {		if(/version (\d+.\d+)(.\d+)?/) {		    if($1 >= 3.1) {			# Version 3.1.0 or later: Downgrade to protocol 30			$rsync = "rsync --protocol 30";		    } else {			$rsync = "rsync";		    }		}	    }	    $rsync or ::die_bug("Cannot figure out version of rsync: @out");	}	return $rsync;    }}package JobQueue;sub new {    my $class = shift;    my $commandref = shift;    my $read_from = shift;    my $context_replace = shift;    my $max_number_of_args = shift;    my $return_files = shift;    my $commandlinequeue = CommandLineQueue->new	($commandref, $read_from, $context_replace, $max_number_of_args,	 $return_files);    my @unget = ();    return bless {        'unget' => \@unget,        'commandlinequeue' => $commandlinequeue,        'total_jobs' => undef,    }, ref($class) || $class;}sub get {    my $self = shift;    if(@{$self->{'unget'}}) {        my $job = shift @{$self->{'unget'}};        return ($job);    } else {        my $commandline = $self->{'commandlinequeue'}->get();        if(defined $commandline) {            my $job = Job->new($commandline);            return $job;        } else {            return undef;        }    }}sub unget {    my $self = shift;    unshift @{$self->{'unget'}}, @_;}sub empty {    my $self = shift;    my $empty = (not @{$self->{'unget'}})	&& $self->{'commandlinequeue'}->empty();    ::debug("run", "JobQueue->empty $empty ");    return $empty;}sub total_jobs {    my $self = shift;    if(not defined $self->{'total_jobs'}) {        my $job;        my @queue;	my $start = time;        while($job = $self->get()) {	    if(time - $start > 10) {		::warning("Reading all arguments takes longer than 10 seconds.\n");		$opt::eta && ::warning("Consider removing --eta.\n");		$opt::bar && ::warning("Consider removing --bar.\n");		last;	    }            push @queue, $job;        }        while($job = $self->get()) {            push @queue, $job;        }        $self->unget(@queue);        $self->{'total_jobs'} = $#queue+1;    }    return $self->{'total_jobs'};}sub next_seq {    my $self = shift;    return $self->{'commandlinequeue'}->seq();}sub quote_args {    my $self = shift;    return $self->{'commandlinequeue'}->quote_args();}package Job;sub new {    my $class = shift;    my $commandlineref = shift;    return bless {        'commandline' => $commandlineref, # CommandLine object        'workdir' => undef, # --workdir        'stdin' => undef, # filehandle for stdin (used for --pipe)	# filename for writing stdout to (used for --files)        'remaining' => "", # remaining data not sent to stdin (used for --pipe)	'datawritten' => 0, # amount of data sent via stdin (used for --pipe)        'transfersize' => 0, # size of files using --transfer        'returnsize' => 0, # size of files using --return        'pid' => undef,        # hash of { SSHLogins => number of times the command failed there }        'failed' => undef,        'sshlogin' => undef,        # The commandline wrapped with rsync and ssh        'sshlogin_wrap' => undef,        'exitstatus' => undef,        'exitsignal' => undef,	# Timestamp for timeout if any	'timeout' => undef,	'virgin' => 1,    }, ref($class) || $class;}sub replaced {    my $self = shift;    $self->{'commandline'} or ::die_bug("commandline empty");    return $self->{'commandline'}->replaced();}sub seq {    my $self = shift;    return $self->{'commandline'}->seq();}sub slot {    my $self = shift;    return $self->{'commandline'}->slot();}{    my($cattail);    sub cattail {	# Returns:	#   $cattail = perl program for: cattail "decompress program" writerpid [file_to_decompress or stdin] [file_to_unlink]	if(not $cattail) {	    $cattail = q{		# cat followed by tail.		# If $writerpid dead: finish after this round		use Fcntl;		$|=1;		my ($cmd, $writerpid, $read_file, $unlink_file) = @ARGV;		if($read_file) {		    open(IN,"<",$read_file) || die("cattail: Cannot open $read_file");		} else {		    *IN = *STDIN;		}		my $flags;		fcntl(IN, F_GETFL, $flags) || die $!; # Get the current flags on the filehandle		$flags |= O_NONBLOCK; # Add non-blocking to the flags		fcntl(IN, F_SETFL, $flags) || die $!; # Set the flags on the filehandle		open(OUT,"|-",$cmd) || die("cattail: Cannot run $cmd");		while(1) {		    # clear EOF		    seek(IN,0,1);		    my $writer_running = kill 0, $writerpid;		    $read = sysread(IN,$buf,32768);		    if($read) {			# We can unlink the file now: The writer has written something			-e $unlink_file and unlink $unlink_file;			# Blocking print			while($buf) {			    my $bytes_written = syswrite(OUT,$buf);			    # syswrite may be interrupted by SIGHUP			    substr($buf,0,$bytes_written) = "";			}			# Something printed: Wait less next time			$sleep /= 2;		    } else {			if(eof(IN) and not $writer_running) {			    # Writer dead: There will never be more to read => exit			    exit;			}			# TODO This could probably be done more efficiently using select(2)			# Nothing read: Wait longer before next read			# Up to 30 milliseconds			$sleep = ($sleep < 30) ? ($sleep * 1.001 + 0.01) : ($sleep);			usleep($sleep);		    }		}		sub usleep {		    # Sleep this many milliseconds.		    my $secs = shift;		    select(undef, undef, undef, $secs/1000);		}	    };	    $cattail =~ s/#.*//mg;	    $cattail =~ s/\s+/ /g;	}	return $cattail;    }}sub openoutputfiles {    # Open files for STDOUT and STDERR    # Set file handles in $self->fh    my $self = shift;    my ($outfhw, $errfhw, $outname, $errname);    if($opt::results) {	my $args_as_dirname = $self->{'commandline'}->args_as_dirname();	# Output in: prefix/name1/val1/name2/val2/stdout	my $dir = $opt::results."/".$args_as_dirname;	if(eval{ File::Path::mkpath($dir); }) {	    # OK	} else {	    # mkpath failed: Argument probably too long.	    # Set $Global::max_file_length, which will keep the individual	    # dir names shorter than the max length	    max_file_name_length($opt::results);	    $args_as_dirname = $self->{'commandline'}->args_as_dirname();	    # prefix/name1/val1/name2/val2/	    $dir = $opt::results."/".$args_as_dirname;	    File::Path::mkpath($dir);	}	# prefix/name1/val1/name2/val2/stdout	$outname = "$dir/stdout";	if(not open($outfhw, "+>", $outname)) {	    ::error("Cannot write to `$outname'.\n");	    ::wait_and_exit(255);	}	# prefix/name1/val1/name2/val2/stderr	$errname = "$dir/stderr";	if(not open($errfhw, "+>", $errname)) {	    ::error("Cannot write to `$errname'.\n");	    ::wait_and_exit(255);	}	$self->set_fh(1,"unlink","");	$self->set_fh(2,"unlink","");    } elsif(not $opt::ungroup) {	# To group we create temporary files for STDOUT and STDERR	# To avoid the cleanup unlink the files immediately (but keep them open)	if(@Global::tee_jobs) {	    # files must be removed when the tee is done	} elsif($opt::files) {	    ($outfhw, $outname) = ::tmpfile(SUFFIX => ".par");	    ($errfhw, $errname) = ::tmpfile(SUFFIX => ".par");	    # --files => only remove stderr	    $self->set_fh(1,"unlink","");	    $self->set_fh(2,"unlink",$errname);	} else {	    ($outfhw, $outname) = ::tmpfile(SUFFIX => ".par");	    ($errfhw, $errname) = ::tmpfile(SUFFIX => ".par");	    $self->set_fh(1,"unlink",$outname);	    $self->set_fh(2,"unlink",$errname);	}    } else {	# --ungroup	open($outfhw,">&",$Global::fd{1}) || die;	open($errfhw,">&",$Global::fd{2}) || die;	# File name must be empty as it will otherwise be printed	$outname = "";	$errname = "";	$self->set_fh(1,"unlink",$outname);	$self->set_fh(2,"unlink",$errname);    }    # Set writing FD    $self->set_fh(1,'w',$outfhw);    $self->set_fh(2,'w',$errfhw);    $self->set_fh(1,'name',$outname);    $self->set_fh(2,'name',$errname);    if($opt::compress) {	# Send stdout to stdin for $opt::compress_program(1)	# Send stderr to stdin for $opt::compress_program(2)	# cattail get pid:  $pid = $self->fh($fdno,'rpid');	my $cattail = cattail();	for my $fdno (1,2) {	    my $wpid = open(my $fdw,"|-","$opt::compress_program >>".			    $self->fh($fdno,'name')) || die $?;	    $self->set_fh($fdno,'w',$fdw);	    $self->set_fh($fdno,'wpid',$wpid);	    my $rpid = open(my $fdr, "-|", "perl", "-e", $cattail,			    $opt::decompress_program, $wpid,			    $self->fh($fdno,'name'),$self->fh($fdno,'unlink')) || die $?;	    $self->set_fh($fdno,'r',$fdr);	    $self->set_fh($fdno,'rpid',$rpid);	}    } elsif(not $opt::ungroup) {	# Set reading FD if using --group (--ungroup does not need)	for my $fdno (1,2) {	    # Re-open the file for reading	    # so fdw can be closed separately	    # and fdr can be seeked separately (for --line-buffer)	    open(my $fdr,"<", $self->fh($fdno,'name')) ||		::die_bug("fdr: Cannot open ".$self->fh($fdno,'name'));	    $self->set_fh($fdno,'r',$fdr);            # Unlink if required	    $Global::debug or unlink $self->fh($fdno,"unlink");	}    }    if($opt::linebuffer) {	# Set non-blocking when using --linebuffer	$Global::use{"Fcntl"} ||= eval "use Fcntl qw(:DEFAULT :flock); 1;";	for my $fdno (1,2) {	    my $fdr = $self->fh($fdno,'r');	    my $flags;	    fcntl($fdr, &F_GETFL, $flags) || die $!; # Get the current flags on the filehandle	    $flags |= &O_NONBLOCK; # Add non-blocking to the flags	    fcntl($fdr, &F_SETFL, $flags) || die $!; # Set the flags on the filehandle	}    }}sub max_file_name_length {    # Figure out the max length of a subdir    # TODO and the max total length    # Ext4 = 255,130816    my $testdir = shift;    my $upper = 8_000_000;    my $len = 8;    my $dir="x"x$len;    do {	rmdir($testdir."/".$dir);	$len *= 16;	$dir="x"x$len;    } while (mkdir $testdir."/".$dir);    # Then search for the actual max length between $len/16 and $len    my $min = $len/16;    my $max = $len;    while($max-$min > 5) {	# If we are within 5 chars of the exact value:	# it is not worth the extra time to find the exact value	my $test = int(($min+$max)/2);	$dir="x"x$test;	if(mkdir $testdir."/".$dir) {	    rmdir($testdir."/".$dir);	    $min = $test;	} else {	    $max = $test;	}    }    $Global::max_file_length = $min;    return $min;}sub set_fh {    # Set file handle    my ($self, $fd_no, $key, $fh) = @_;    $self->{'fd'}{$fd_no,$key} = $fh;}sub fh {    # Get file handle    my ($self, $fd_no, $key) = @_;    return $self->{'fd'}{$fd_no,$key};}sub write {    my $self = shift;    my $remaining_ref = shift;    my $stdin_fh = $self->fh(0,"w");    syswrite($stdin_fh,$$remaining_ref);}sub set_stdin_buffer {    # Copy stdin buffer from $block_ref up to $endpos    # Prepend with $header_ref    # Remove $recstart and $recend if needed    # Input:    #   $header_ref = ref to $header to prepend    #   $block_ref = ref to $block to pass on    #   $endpos = length of $block to pass on    #   $recstart = --recstart regexp    #   $recend = --recend regexp    # Returns:    #   N/A    my $self = shift;    my ($header_ref,$block_ref,$endpos,$recstart,$recend) = @_;    $self->{'stdin_buffer'} = ($self->virgin() ? $$header_ref : "").substr($$block_ref,0,$endpos);    if($opt::remove_rec_sep) {	remove_rec_sep(\$self->{'stdin_buffer'},$recstart,$recend);    }    $self->{'stdin_buffer_length'} = length $self->{'stdin_buffer'};    $self->{'stdin_buffer_pos'} = 0;}sub stdin_buffer_length {    my $self = shift;    return $self->{'stdin_buffer_length'};}sub remove_rec_sep {    my ($block_ref,$recstart,$recend) = @_;    # Remove record separator    $$block_ref =~ s/$recend$recstart//gos;    $$block_ref =~ s/^$recstart//os;    $$block_ref =~ s/$recend$//os;}sub non_block_write {    my $self = shift;    my $something_written = 0;    use POSIX qw(:errno_h);#    use Fcntl;#    my $flags = '';    for my $buf (substr($self->{'stdin_buffer'},$self->{'stdin_buffer_pos'})) {	my $in = $self->fh(0,"w");#	fcntl($in, F_GETFL, $flags)#	    or die "Couldn't get flags for HANDLE : $!\n";#	$flags |= O_NONBLOCK;#	fcntl($in, F_SETFL, $flags)#	    or die "Couldn't set flags for HANDLE: $!\n";	my $rv = syswrite($in, $buf);	if (!defined($rv) && $! == EAGAIN) {	    # would block	    $something_written = 0;	} elsif ($self->{'stdin_buffer_pos'}+$rv != $self->{'stdin_buffer_length'}) {	    # incomplete write	    # Remove the written part	    $self->{'stdin_buffer_pos'} += $rv;	    $something_written = $rv;	} else {	    # successfully wrote everything	    my $a="";	    $self->set_stdin_buffer(\$a,\$a,"","");	    $something_written = $rv;	}    }    ::debug("pipe", "Non-block: ", $something_written);    return $something_written;}sub virgin {    my $self = shift;    return $self->{'virgin'};}sub set_virgin {    my $self = shift;    $self->{'virgin'} = shift;}sub pid {    my $self = shift;    return $self->{'pid'};}sub set_pid {    my $self = shift;    $self->{'pid'} = shift;}sub starttime {    # Returns:    #   UNIX-timestamp this job started    my $self = shift;    return sprintf("%.3f",$self->{'starttime'});}sub set_starttime {    my $self = shift;    my $starttime = shift || ::now();    $self->{'starttime'} = $starttime;}sub runtime {    # Returns:    #   Run time in seconds    my $self = shift;    return sprintf("%.3f",int(($self->endtime() - $self->starttime())*1000)/1000);}sub endtime {    # Returns:    #   UNIX-timestamp this job ended    #   0 if not ended yet    my $self = shift;    return ($self->{'endtime'} || 0);}sub set_endtime {    my $self = shift;    my $endtime = shift;    $self->{'endtime'} = $endtime;}sub timedout {    # Is the job timedout?    # Input:    #   $delta_time = time that the job may run    # Returns:    #   True or false    my $self = shift;    my $delta_time = shift;    return time > $self->{'starttime'} + $delta_time;}sub kill {    # Kill the job.    # Send the signals to (grand)*children and pid.    # If no signals: TERM TERM KILL    # Wait 200 ms after each TERM.    # Input:    #   @signals = signals to send    my $self = shift;    my @signals = @_;    my @family_pids = $self->family_pids();    # Record this jobs as failed    $self->set_exitstatus(-1);    # Send two TERMs to give time to clean up    ::debug("run", "Kill seq ", $self->seq(), "\n");    my @send_signals = @signals || ("TERM", "TERM", "KILL");    for my $signal (@send_signals) {	my $alive = 0;	for my $pid (@family_pids) {	    if(kill 0, $pid) {		# The job still running		kill $signal, $pid;		$alive = 1;	    }	}	# If a signal was given as input, do not do the sleep below	@signals and next;	if($signal eq "TERM" and $alive) {	    # Wait up to 200 ms between TERMs - but only if any pids are alive	    my $sleep = 1;	    for (my $sleepsum = 0; kill 0, $family_pids[0] and $sleepsum < 200;		 $sleepsum += $sleep) {		$sleep = ::reap_usleep($sleep);	    }	}    }}sub family_pids {    # Find the pids with this->pid as (grand)*parent    # Returns:    #   @pids = pids of (grand)*children    my $self = shift;    my $pid = $self->pid();    my @pids;    my ($children_of_ref, $parent_of_ref, $name_of_ref) = ::pid_table();    my @more = ($pid);    # While more (grand)*children    while(@more) {	my @m;	push @pids, @more;	for my $parent (@more) {	    if($children_of_ref->{$parent}) {		# add the children of this parent		push @m, @{$children_of_ref->{$parent}};	    }	}	@more = @m;    }    return (@pids);}sub failed {    # return number of times failed for this $sshlogin    # Input:    #   $sshlogin    # Returns:    #   Number of times failed for $sshlogin    my $self = shift;    my $sshlogin = shift;    return $self->{'failed'}{$sshlogin};}sub failed_here {    # return number of times failed for the current $sshlogin    # Returns:    #   Number of times failed for this sshlogin    my $self = shift;    return $self->{'failed'}{$self->sshlogin()};}sub add_failed {    # increase the number of times failed for this $sshlogin    my $self = shift;    my $sshlogin = shift;    $self->{'failed'}{$sshlogin}++;}sub add_failed_here {    # increase the number of times failed for the current $sshlogin    my $self = shift;    $self->{'failed'}{$self->sshlogin()}++;}sub reset_failed {    # increase the number of times failed for this $sshlogin    my $self = shift;    my $sshlogin = shift;    delete $self->{'failed'}{$sshlogin};}sub reset_failed_here {    # increase the number of times failed for this $sshlogin    my $self = shift;    delete $self->{'failed'}{$self->sshlogin()};}sub min_failed {    # Returns:    #   the number of sshlogins this command has failed on    #   the minimal number of times this command has failed    my $self = shift;    my $min_failures =	::min(map { $self->{'failed'}{$_} } keys %{$self->{'failed'}});    my $number_of_sshlogins_failed_on = scalar keys %{$self->{'failed'}};    return ($number_of_sshlogins_failed_on,$min_failures);}sub total_failed {    # Returns:    #   $total_failures = the number of times this command has failed    my $self = shift;    my $total_failures = 0;    for (values %{$self->{'failed'}}) {	$total_failures += $_;    }    return $total_failures;}sub wrapped {    # Wrap command with:    # * --shellquote    # * --nice    # * --cat    # * --fifo    # * --sshlogin    # * --pipepart (@Global::cat_partials)    # * --pipe    # * --tmux    # The ordering of the wrapping is important:    # * --nice/--cat/--fifo should be done on the remote machine    # * --pipepart/--pipe should be done on the local machine inside --tmux    # Uses:    #   $Global::envvar    #   $opt::shellquote    #   $opt::nice    #   $Global::shell    #   $opt::cat    #   $opt::fifo    #   @Global::cat_partials    #   $opt::pipe    #   $opt::tmux    # Returns:    #   $self->{'wrapped'} = the command wrapped with the above    my $self = shift;    if(not defined $self->{'wrapped'}) {	my $command = $Global::envvar.$self->replaced();	if($opt::shellquote) {	    # Prepend echo	    # and quote twice	    $command = "echo " .		::shell_quote_scalar(::shell_quote_scalar($command));	}	if($opt::nice) {	    # Prepend \nice -n19 $SHELL -c	    # and quote.	    # The '\' before nice is needed to avoid tcsh's built-in	    $command = '\nice'. " -n". $opt::nice. " ".		$Global::shell. " -c ".		::shell_quote_scalar($command);	}	if($opt::cat) {	    # Prepend 'cat > {};'	    # Append '_EXIT=$?;(rm {};exit $_EXIT)'	    $command =		$self->{'commandline'}->replace_placeholders(["cat > \257<\257>; "], 0, 0).		$command.		$self->{'commandline'}->replace_placeholders(		    ["; _EXIT=\$?; rm \257<\257>; exit \$_EXIT"], 0, 0);	} elsif($opt::fifo) {	    # Prepend 'mkfifo {}; ('	    # Append ') & _PID=$!; cat > {}; wait $_PID; _EXIT=$?;(rm {};exit $_EXIT)'	    $command =		$self->{'commandline'}->replace_placeholders(["mkfifo \257<\257>; ("], 0, 0).		$command.		$self->{'commandline'}->replace_placeholders([") & _PID=\$!; cat > \257<\257>; ",					    "wait \$_PID; _EXIT=\$?; ",					    "rm \257<\257>; exit \$_EXIT"],					    0,0);	}	# Wrap with ssh + tranferring of files	$command = $self->sshlogin_wrap($command);	if(@Global::cat_partials) {	    # Prepend:	    # < /tmp/foo perl -e 'while(@ARGV) { sysseek(STDIN,shift,0) || die; $left = shift; while($read = sysread(STDIN,$buf, ($left > 32768 ? 32768 : $left))){ $left -= $read; syswrite(STDOUT,$buf); } }'  0 0 0 11 |	    $command = (shift @Global::cat_partials). "|". "(". $command. ")";	} elsif($opt::pipe) {	    # Prepend EOF-detector to avoid starting $command if EOF.	    # The $tmpfile might exist if run on a remote system - we accept that risk	    my ($dummy_fh, $tmpfile) = ::tmpfile(SUFFIX => ".chr");	    # Unlink to avoid leaving files if --dry-run or --sshlogin	    unlink $tmpfile;	    $command =		# Exit value:		#   empty input = true		#   some input = exit val from command		qq{ sh -c 'dd bs=1 count=1 of=$tmpfile 2>/dev/null'; }.		qq{ test \! -s "$tmpfile" && rm -f "$tmpfile" && exec true; }.		qq{ (cat $tmpfile; rm $tmpfile; cat - ) | }.		"($command);";	}	if($opt::tmux) {	    # Wrap command with 'tmux'	    $command = $self->tmux_wrap($command);	}	$self->{'wrapped'} = $command;    }    return $self->{'wrapped'};}sub set_sshlogin {    my $self = shift;    my $sshlogin = shift;    $self->{'sshlogin'} = $sshlogin;    delete $self->{'sshlogin_wrap'}; # If sshlogin is changed the wrap is wrong    delete $self->{'wrapped'};}sub sshlogin {    my $self = shift;    return $self->{'sshlogin'};}sub sshlogin_wrap {    # Wrap the command with the commands needed to run remotely    # Returns:    #   $self->{'sshlogin_wrap'} = command wrapped with ssh+transfer commands    my $self = shift;    my $command = shift;    if(not defined $self->{'sshlogin_wrap'}) {	my $sshlogin = $self->sshlogin();	my $sshcmd = $sshlogin->sshcommand();	my $serverlogin = $sshlogin->serverlogin();	my ($pre,$post,$cleanup)=("","","");	if($serverlogin eq ":") {	    # No transfer neeeded	    $self->{'sshlogin_wrap'} = $command;	} else {	    # --transfer	    $pre .= $self->sshtransfer();	    # --return	    $post .= $self->sshreturn();	    # --cleanup	    $post .= $self->sshcleanup();	    if($post) {		# We need to save the exit status of the job		$post = '_EXIT_status=$?; ' . $post . ' exit $_EXIT_status;';	    }	    # If the remote login shell is (t)csh then use 'setenv'	    # otherwise use 'export'	    # We cannot use parse_env_var(), as PARALLEL_SEQ changes	    # for each command	    my $parallel_env =		($Global::envwarn		 . q{ 'eval `echo $SHELL | grep "/t\\{0,1\\}csh" > /dev/null }		 . q{ && echo setenv PARALLEL_SEQ '$PARALLEL_SEQ'\; }		 . q{ setenv PARALLEL_PID '$PARALLEL_PID' }		 . q{ || echo PARALLEL_SEQ='$PARALLEL_SEQ'\;export PARALLEL_SEQ\; }		 . q{ PARALLEL_PID='$PARALLEL_PID'\;export PARALLEL_PID` ;' });	    my $remote_pre = "";	    my $ssh_options = "";	    if(($opt::pipe or $opt::pipepart) and $opt::ctrlc	       or	       not ($opt::pipe or $opt::pipepart) and not $opt::noctrlc) {		# TODO Determine if this is needed		# Propagating CTRL-C to kill remote jobs requires		# remote jobs to be run with a terminal.		$ssh_options = "-tt -oLogLevel=quiet";#		$ssh_options = "";		# tty - check if we have a tty.		# stty:		#   -onlcr - make output 8-bit clean		#   isig - pass CTRL-C as signal		#   -echo - do not echo input		$remote_pre .= ::shell_quote_scalar('tty >/dev/null && stty isig -onlcr -echo;');	    }	    if($opt::workdir) {		my $wd = ::shell_quote_file($self->workdir());		$remote_pre .= ::shell_quote_scalar("mkdir -p ") . $wd .		    ::shell_quote_scalar("; cd ") . $wd .		    # exit 255 (instead of exec false) would be the correct thing,		    # but that fails on tcsh		    ::shell_quote_scalar(qq{ || exec false;});	    }	    # This script is to solve the problem of	    # * not mixing STDERR and STDOUT	    # * terminating with ctrl-c	    # It works on Linux but not Solaris	    # Finishes on Solaris, but wrong exit code:	    # $SIG{CHLD} = sub {exit ($?&127 ? 128+($?&127) : 1+$?>>8)};	    # Hangs on Solaris, but correct exit code on Linux:	    # $SIG{CHLD} = sub { $done = 1 };	    # $p->poll;	    my $signal_script = "perl -e '".	    q{		use IO::Poll;                $SIG{CHLD} = sub { $done = 1 };		$p = IO::Poll->new;		$p->mask(STDOUT, POLLHUP);		$pid=fork; unless($pid) {setpgrp; exec $ENV{SHELL}, "-c", @ARGV; die "exec: $!\n"}                $p->poll;		kill SIGHUP, -${pid} unless $done;		wait; exit ($?&127 ? 128+($?&127) : 1+$?>>8)            } . "' ";	    $signal_script =~ s/\s+/ /g;	    $self->{'sshlogin_wrap'} =		($pre		 . "$sshcmd $ssh_options $serverlogin $parallel_env "		 . $remote_pre#		 . ::shell_quote_scalar($signal_script . ::shell_quote_scalar($command))		 . ::shell_quote_scalar($command)		 . ";"		 . $post);	}    }    return $self->{'sshlogin_wrap'};}sub transfer {    # Files to transfer    # Returns:    #   @transfer - File names of files to transfer    my $self = shift;    my @transfer = ();    $self->{'transfersize'} = 0;    if($opt::transfer) {	for my $record (@{$self->{'commandline'}{'arg_list'}}) {	    # Merge arguments from records into args	    for my $arg (@$record) {		CORE::push @transfer, $arg->orig();		# filesize		if(-e $arg->orig()) {		    $self->{'transfersize'} += (stat($arg->orig()))[7];		}	    }	}    }    return @transfer;}sub transfersize {    my $self = shift;    return $self->{'transfersize'};}sub sshtransfer {    # Returns for each transfer file:    #   rsync $file remote:$workdir    my $self = shift;    my @pre;    my $sshlogin = $self->sshlogin();    my $workdir = $self->workdir();    for my $file ($self->transfer()) {      push @pre, $sshlogin->rsync_transfer_cmd($file,$workdir).";";    }    return join("",@pre);}sub return {    # Files to return    # Non-quoted and with {...} substituted    # Returns:    #   @non_quoted_filenames    my $self = shift;    return $self->{'commandline'}->	replace_placeholders($self->{'commandline'}{'return_files'},0,0);}sub returnsize {    # This is called after the job has finished    # Returns:    #   $number_of_bytes transferred in return    my $self = shift;    for my $file ($self->return()) {	if(-e $file) {	    $self->{'returnsize'} += (stat($file))[7];	}    }    return $self->{'returnsize'};}sub sshreturn {    # Returns for each return-file:    #   rsync remote:$workdir/$file .    my $self = shift;    my $sshlogin = $self->sshlogin();    my $sshcmd = $sshlogin->sshcommand();    my $serverlogin = $sshlogin->serverlogin();    my $rsync_opt = "-rlDzR -e".::shell_quote_scalar($sshcmd);    my $pre = "";    for my $file ($self->return()) {	$file =~ s:^\./::g; # Remove ./ if any	my $relpath = ($file !~ m:^/:); # Is the path relative?	my $cd = "";	my $wd = "";	if($relpath) {	    #   rsync -avR /foo/./bar/baz.c remote:/tmp/	    # == (on old systems)	    #   rsync -avR --rsync-path="cd /foo; rsync" remote:bar/baz.c /tmp/	    $wd = ::shell_quote_file($self->workdir()."/");	}	# Only load File::Basename if actually needed	$Global::use{"File::Basename"} ||= eval "use File::Basename; 1;";	# dir/./file means relative to dir, so remove dir on remote	$file =~ m:(.*)/\./:;	my $basedir = $1 ? ::shell_quote_file($1."/") : "";	my $nobasedir = $file;	$nobasedir =~ s:.*/\./::;	$cd = ::shell_quote_file(::dirname($nobasedir));	my $rsync_cd = '--rsync-path='.::shell_quote_scalar("cd $wd$cd; rsync");	my $basename = ::shell_quote_scalar(::shell_quote_file(basename($file)));	# --return	#   mkdir -p /home/tange/dir/subdir/;        #   rsync (--protocol 30) -rlDzR --rsync-path="cd /home/tange/dir/subdir/; rsync"        #   server:file.gz /home/tange/dir/subdir/	$pre .= "mkdir -p $basedir$cd; ".$sshlogin->rsync()." $rsync_cd $rsync_opt $serverlogin:".	     $basename . " ".$basedir.$cd.";";    }    return $pre;}sub sshcleanup {    # Return the sshcommand needed to remove the file    # Returns:    #   ssh command needed to remove files from sshlogin    my $self = shift;    my $sshlogin = $self->sshlogin();    my $sshcmd = $sshlogin->sshcommand();    my $serverlogin = $sshlogin->serverlogin();    my $workdir = $self->workdir();    my $cleancmd = "";    for my $file ($self->cleanup()) {	my @subworkdirs = parentdirs_of($file);	$cleancmd .= $sshlogin->cleanup_cmd($file,$workdir).";";    }    if(defined $opt::workdir and $opt::workdir eq "...") {	$cleancmd .= "$sshcmd $serverlogin rm -rf " . ::shell_quote_scalar($workdir).';';    }    return $cleancmd;}sub cleanup {    # Returns:    #   Files to remove at cleanup    my $self = shift;    if($opt::cleanup) {	my @transfer = $self->transfer();	my @return = $self->return();	return (@transfer,@return);    } else {	return ();    }}sub workdir {    # Returns:    #   the workdir on a remote machine    my $self = shift;    if(not defined $self->{'workdir'}) {	my $workdir;	if(defined $opt::workdir) {	    if($opt::workdir eq ".") {		# . means current dir		my $home = $ENV{'HOME'};		eval 'use Cwd';		my $cwd = cwd();		$workdir = $cwd;		if($home) {		    # If homedir exists: remove the homedir from		    # workdir if cwd starts with homedir		    # E.g. /home/foo/my/dir => my/dir		    # E.g. /tmp/my/dir => /tmp/my/dir		    my ($home_dev, $home_ino) = (stat($home))[0,1];		    my $parent = "";		    my @dir_parts = split(m:/:,$cwd);		    my $part;		    while(defined ($part = shift @dir_parts)) {			$part eq "" and next;			$parent .= "/".$part;			my ($parent_dev, $parent_ino) = (stat($parent))[0,1];			if($parent_dev == $home_dev and $parent_ino == $home_ino) {			    # dev and ino is the same: We found the homedir.			    $workdir = join("/",@dir_parts);			    last;			}		    }		}		if($workdir eq "") {		    $workdir = ".";		}	    } elsif($opt::workdir eq "...") {		$workdir = ".parallel/tmp/" . ::hostname() . "-" . $$		    . "-" . $self->seq();	    } else {		$workdir = $opt::workdir;		# Rsync treats /./ special. We dont want that		$workdir =~ s:/\./:/:g; # Remove /./		$workdir =~ s:/+$::; # Remove ending / if any		$workdir =~ s:^\./::g; # Remove starting ./ if any	    }	} else {	    $workdir = ".";	}	$self->{'workdir'} = ::shell_quote_scalar($workdir);    }    return $self->{'workdir'};}sub parentdirs_of {    # Return:    #   all parentdirs except . of this dir or file - sorted desc by length    my $d = shift;    my @parents = ();    while($d =~ s:/[^/]+$::) {	if($d ne ".") {	    push @parents, $d;	}    }    return @parents;}sub start {    # Setup STDOUT and STDERR for a job and start it.    # Returns:    #   job-object or undef if job not to run    my $job = shift;    # Get the shell command to be executed (possibly with ssh infront).    my $command = $job->wrapped();    if($Global::interactive or $Global::stderr_verbose) {	if($Global::interactive) {	    print $Global::original_stderr "$command ?...";	    open(my $tty_fh, "<", "/dev/tty") || ::die_bug("interactive-tty");	    my $answer = <$tty_fh>;	    close $tty_fh;	    my $run_yes = ($answer =~ /^\s*y/i);	    if (not $run_yes) {		$command = "true"; # Run the command 'true'	    }	} else {	    print $Global::original_stderr "$command\n";	}    }    my $pid;    $job->openoutputfiles();    my($stdout_fh,$stderr_fh) = ($job->fh(1,"w"),$job->fh(2,"w"));    local (*IN,*OUT,*ERR);    open OUT, '>&', $stdout_fh or ::die_bug("Can't redirect STDOUT: $!");    open ERR, '>&', $stderr_fh or ::die_bug("Can't dup STDOUT: $!");    if(($opt::dryrun or $Global::verbose) and $opt::ungroup) {	if($Global::verbose <= 1) {	    print $stdout_fh $job->replaced(),"\n";	} else {	    # Verbose level > 1: Print the rsync and stuff	    print $stdout_fh $command,"\n";	}    }    if($opt::dryrun) {	$command = "true";    }    $ENV{'PARALLEL_SEQ'} = $job->seq();    $ENV{'PARALLEL_PID'} = $$;    ::debug("run", $Global::total_running, " processes . Starting (",	    $job->seq(), "): $command\n");    if($opt::pipe) {	my ($stdin_fh);	# The eval is needed to catch exception from open3	eval {	    $pid = ::open3($stdin_fh, ">&OUT", ">&ERR", $Global::shell, "-c", $command) ||		::die_bug("open3-pipe");	    1;	};	$job->set_fh(0,"w",$stdin_fh);    } elsif(@opt::a and not $Global::stdin_in_opt_a and $job->seq() == 1	    and $job->sshlogin()->string() eq ":") {	# Give STDIN to the first job if using -a (but only if running	# locally - otherwise CTRL-C does not work for other jobs Bug#36585)	*IN = *STDIN;	# The eval is needed to catch exception from open3	eval {	    $pid = ::open3("<&IN", ">&OUT", ">&ERR", $Global::shell, "-c", $command) ||		::die_bug("open3-a");	    1;	};	# Re-open to avoid complaining	open(STDIN, "<&", $Global::original_stdin)	    or ::die_bug("dup-\$Global::original_stdin: $!");    } elsif ($opt::tty and not $Global::tty_taken and -c "/dev/tty" and	     open(my $devtty_fh, "<", "/dev/tty")) {	# Give /dev/tty to the command if no one else is using it	*IN = $devtty_fh;	# The eval is needed to catch exception from open3	eval {	    $pid = ::open3("<&IN", ">&OUT", ">&ERR", $Global::shell, "-c", $command) ||		::die_bug("open3-/dev/tty");	    $Global::tty_taken = $pid;	    close $devtty_fh;	    1;	};    } else {	# The eval is needed to catch exception from open3	eval {	    $pid = ::open3(::gensym, ">&OUT", ">&ERR", $Global::shell, "-c", $command) ||		::die_bug("open3-gensym");	    1;	};    }    if($pid) {	# A job was started	$Global::total_running++;	$Global::total_started++;	$job->set_pid($pid);	$job->set_starttime();	$Global::running{$job->pid()} = $job;	if($opt::timeout) {	    $Global::timeoutq->insert($job);	}	$Global::newest_job = $job;	$Global::newest_starttime = ::now();	return $job;    } else {	# No more processes	::debug("run", "Cannot spawn more jobs.\n");	return undef;    }}sub tmux_wrap {    # Wrap command with tmux for session pPID    # Input:    #   $actual_command = the actual command being run (incl ssh wrap)    my $self = shift;    my $actual_command = shift;    # Temporary file name. Used for fifo to communicate exit val    my ($fh, $tmpfile) = ::tmpfile(SUFFIX => ".tmx");    $Global::unlink{$tmpfile}=1;    close $fh;    unlink $tmpfile;    my $visual_command = $self->replaced();    my $title = $visual_command;    # ; causes problems    # ascii 194-245 annoys tmux    $title =~ tr/[\011-\016;\302-\365]//d;    my $tmux;    if($Global::total_running == 0) {	$tmux = "tmux new-session -s p$$ -d -n ".	    ::shell_quote_scalar($title);	print $Global::original_stderr "See output with: tmux attach -t p$$\n";    } else {	$tmux = "tmux new-window -t p$$ -n ".::shell_quote_scalar($title);    }    return "mkfifo $tmpfile; $tmux ".	# Run in tmux	::shell_quote_scalar(	"(".$actual_command.');(echo $?$status;echo 255) >'.$tmpfile."&".	"echo ".::shell_quote_scalar($visual_command).";".	"echo \007Job finished at: `date`;sleep 10").	# Run outside tmux	# Read the first line from the fifo and use that as status code	";  exit `perl -ne 'unlink \$ARGV; 1..1 and print' $tmpfile` ";}sub is_already_in_results {    # Do we already have results for this job?    # Returns:    #   $job_already_run = bool whether there is output for this or not    my $job = $_[0];    my $args_as_dirname = $job->{'commandline'}->args_as_dirname();    # prefix/name1/val1/name2/val2/    my $dir = $opt::results."/".$args_as_dirname;    ::debug("run", "Test $dir/stdout", -e "$dir/stdout", "\n");    return -e "$dir/stdout";}sub is_already_in_joblog {    my $job = shift;    return vec($Global::job_already_run,$job->seq(),1);}sub set_job_in_joblog {    my $job = shift;    vec($Global::job_already_run,$job->seq(),1) = 1;}sub should_be_retried {    # Should this job be retried?    # Returns    #   0 - do not retry    #   1 - job queued for retry    my $self = shift;    if (not $opt::retries) {	return 0;    }    if(not $self->exitstatus()) {	# Completed with success. If there is a recorded failure: forget it	$self->reset_failed_here();	return 0    } else {	# The job failed. Should it be retried?	$self->add_failed_here();	if($self->total_failed() == $opt::retries) {	    # This has been retried enough	    return 0;	} else {	    # This command should be retried	    $self->set_endtime(undef);	    $Global::JobQueue->unget($self);	    ::debug("run", "Retry ", $self->seq(), "\n");	    return 1;	}    }}sub print {    # Print the output of the jobs    # Returns: N/A    my $self = shift;    ::debug("print", ">>joboutput ", $self->replaced(), "\n");    if($opt::dryrun) {	# Nothing was printed to this job:	# cleanup tmp files if --files was set	unlink $self->fh(1,"name");    }    if($opt::pipe and $self->virgin()) {	# Skip --joblog, --dryrun, --verbose    } else {	if($Global::joblog and defined $self->{'exitstatus'}) {	    # Add to joblog when finished	    $self->print_joblog();	}	# Printing is only relevant for grouped/--line-buffer output.	$opt::ungroup and return;	# Check for disk full	exit_if_disk_full();	if(($opt::dryrun or $Global::verbose)	   and	   not $self->{'verbose_printed'}) {	    $self->{'verbose_printed'}++;	    if($Global::verbose <= 1) {		print STDOUT $self->replaced(),"\n";	    } else {		# Verbose level > 1: Print the rsync and stuff		print STDOUT $self->wrapped(),"\n";	    }	    # If STDOUT and STDERR are merged,	    # we want the command to be printed first	    # so flush to avoid STDOUT being buffered	    flush STDOUT;	}    }    for my $fdno (sort { $a <=> $b } keys %Global::fd) {	# Sort by file descriptor numerically: 1,2,3,..,9,10,11	$fdno == 0 and next;	my $out_fd = $Global::fd{$fdno};	my $in_fh = $self->fh($fdno,"r");	if(not $in_fh) {	    if(not $Job::file_descriptor_warning_printed{$fdno}++) {		# ::warning("File descriptor $fdno not defined\n");	    }	    next;	}	::debug("print", "File descriptor $fdno (", $self->fh($fdno,"name"), "):");	if($opt::files) {	    # If --compress: $in_fh must be closed first.	    close $self->fh($fdno,"w");	    close $in_fh;	    if($opt::pipe and $self->virgin()) {		# Nothing was printed to this job:		# cleanup unused tmp files if --files was set		for my $fdno (1,2) {		    unlink $self->fh($fdno,"name");		    unlink $self->fh($fdno,"unlink");		}	    } elsif($fdno == 1 and $self->fh($fdno,"name")) {		print $out_fd $self->fh($fdno,"name"),"\n";	    }	} elsif($opt::linebuffer) {	    # Line buffered print out	    $self->linebuffer_print($fdno,$in_fh,$out_fd);	} else {	    my $buf;	    close $self->fh($fdno,"w");	    seek $in_fh, 0, 0;	    # $in_fh is now ready for reading at position 0	    if($opt::tag or defined $opt::tagstring) {		my $tag = $self->tag();		if($fdno == 2) {		    # OpenSSH_3.6.1p2 gives 'tcgetattr: Invalid argument' with -tt		    # This is a crappy way of ignoring it.		    while(<$in_fh>) {			if(/^(client_process_control: )?tcgetattr: Invalid argument\n/) {			    # Skip			} else {			    print $out_fd $tag,$_;			}			# At most run the loop once			last;		    }		}		while(<$in_fh>) {		    print $out_fd $tag,$_;		}	    } else {		my $buf;		if($fdno == 2) {		    # OpenSSH_3.6.1p2 gives 'tcgetattr: Invalid argument' with -tt		    # This is a crappy way of ignoring it.		    sysread($in_fh,$buf,1_000);		    $buf =~ s/^(client_process_control: )?tcgetattr: Invalid argument\n//;		    print $out_fd $buf;		}		while(sysread($in_fh,$buf,32768)) {		    print $out_fd $buf;		}	    }	    close $in_fh;	}	flush $out_fd;    }    ::debug("print", "<<joboutput @command\n");}sub linebuffer_print {    my $self = shift;    my ($fdno,$in_fh,$out_fd) = @_;    my $partial = \$self->{'partial_line',$fdno};    if(defined $self->{'exitstatus'}) {	# If the job is dead: close printing fh. Needed for --compress	close $self->fh($fdno,"w");	if($opt::compress) {	    # Blocked reading in final round	    $Global::use{"Fcntl"} ||= eval "use Fcntl qw(:DEFAULT :flock); 1;";	    for my $fdno (1,2) {		my $fdr = $self->fh($fdno,'r');		my $flags;		fcntl($fdr, &F_GETFL, $flags) || die $!; # Get the current flags on the filehandle		$flags &= ~&O_NONBLOCK; # Remove non-blocking to the flags		fcntl($fdr, &F_SETFL, $flags) || die $!; # Set the flags on the filehandle	    }	}    }    # This seek will clear EOF    seek $in_fh, tell($in_fh), 0;    # The read is non-blocking: The $in_fh is set to non-blocking.    # 32768 --tag = 5.1s    # 327680 --tag = 4.4s    # 1024000 --tag = 4.4s    # 3276800 --tag = 4.3s    # 32768000 --tag = 4.7s    # 10240000 --tag = 4.3s    while(read($in_fh,substr($$partial,length $$partial),3276800)) {	# Append to $$partial	# Find the last \n	my $i = rindex($$partial,"\n");	if($i != -1) {	    # One or more complete lines were found	    if($fdno == 2 and not $self->{'printed_first_line',$fdno}++) {		# OpenSSH_3.6.1p2 gives 'tcgetattr: Invalid argument' with -tt		# This is a crappy way of ignoring it.		$$partial =~ s/^(client_process_control: )?tcgetattr: Invalid argument\n//;		# Length of partial line has changed: Find the last \n again		$i = rindex($$partial,"\n");	    }	    if($opt::tag or defined $opt::tagstring) {		# Replace ^ with $tag within the full line		my $tag = $self->tag();		substr($$partial,0,$i+1) =~ s/^/$tag/gm;		# Length of partial line has changed: Find the last \n again		$i = rindex($$partial,"\n");	    }	    # Print up to and including the last \n	    print $out_fd substr($$partial,0,$i+1);	    # Remove the printed part	    substr($$partial,0,$i+1)="";	}    }    if(defined $self->{'exitstatus'}) {	# If the job is dead: print the remaining partial line	# read remaining	if($$partial and ($opt::tag or defined $opt::tagstring)) {	    my $tag = $self->tag();	    $$partial =~ s/^/$tag/gm;	}	print $out_fd $$partial;	# Release the memory	$$partial = undef;	if($self->fh($fdno,"rpid") and CORE::kill 0, $self->fh($fdno,"rpid")) {	    # decompress still running	} else {	    # decompress done: close fh	    close $in_fh;	}    }}sub print_joblog {    my $self = shift;    my $cmd;    if($Global::verbose <= 1) {	$cmd = $self->replaced();    } else {	# Verbose level > 1: Print the rsync and stuff	$cmd = "@command";    }    print $Global::joblog	join("\t", $self->seq(), $self->sshlogin()->string(),	     $self->starttime(), sprintf("%10.3f",$self->runtime()),	     $self->transfersize(), $self->returnsize(),	     $self->exitstatus(), $self->exitsignal(), $cmd	). "\n";    flush $Global::joblog;    $self->set_job_in_joblog();}sub tag {    my $self = shift;    if(not defined $self->{'tag'}) {	$self->{'tag'} = $self->{'commandline'}->	    replace_placeholders([$opt::tagstring],0,0)."\t";    }    return $self->{'tag'};}sub hostgroups {    my $self = shift;    if(not defined $self->{'hostgroups'}) {	$self->{'hostgroups'} = $self->{'commandline'}->{'arg_list'}[0][0]->{'hostgroups'};    }    return @{$self->{'hostgroups'}};}sub exitstatus {    my $self = shift;    return $self->{'exitstatus'};}sub set_exitstatus {    my $self = shift;    my $exitstatus = shift;    if($exitstatus) {	# Overwrite status if non-zero	$self->{'exitstatus'} = $exitstatus;    } else {	# Set status but do not overwrite	# Status may have been set by --timeout	$self->{'exitstatus'} ||= $exitstatus;    }}sub exitsignal {    my $self = shift;    return $self->{'exitsignal'};}sub set_exitsignal {    my $self = shift;    my $exitsignal = shift;    $self->{'exitsignal'} = $exitsignal;}{    my ($disk_full_fh, $b8193, $name);    sub exit_if_disk_full {	# Checks if $TMPDIR is full by writing 8kb to a tmpfile	# If the disk is full: Exit immediately.	# Returns:	#   N/A	if(not $disk_full_fh) {	    ($disk_full_fh, $name) = ::tmpfile(SUFFIX => ".df");	    unlink $name;	    $b8193 = "x"x8193;	}	# Linux does not discover if a disk is full if writing <= 8192	# Tested on:	# bfs btrfs cramfs ext2 ext3 ext4 ext4dev jffs2 jfs minix msdos	# ntfs reiserfs tmpfs ubifs vfat xfs	# TODO this should be tested on different OS similar to this:	#	# doit() {	#   sudo mount /dev/ram0 /mnt/loop; sudo chmod 1777 /mnt/loop	#   seq 100000 | parallel --tmpdir /mnt/loop/ true &	#   seq 6900000 > /mnt/loop/i && echo seq OK	#   seq 6980868 > /mnt/loop/i	#   seq 10000 > /mnt/loop/ii	#   sleep 3	#   sudo umount /mnt/loop/ || sudo umount -l /mnt/loop/	#   echo >&2	# }	print $disk_full_fh $b8193;	if(not $disk_full_fh	   or	   tell $disk_full_fh == 0) {	    ::error("Output is incomplete. Cannot append to buffer file in $ENV{'TMPDIR'}. Is the disk full?\n");	    ::error("Change \$TMPDIR with --tmpdir or use --compress.\n");	    ::wait_and_exit(255);	}	truncate $disk_full_fh, 0;	seek($disk_full_fh, 0, 0) || die;    }}package CommandLine;sub new {    my $class = shift;    my $seq = shift;    my $commandref = shift;    $commandref || die;    my $arg_queue = shift;    my $context_replace = shift;    my $max_number_of_args = shift; # for -N and normal (-n1)    my $return_files = shift;    my $replacecount_ref = shift;    my $len_ref = shift;    my %replacecount = %$replacecount_ref;    my %len = %$len_ref;    for (keys %$replacecount_ref) {	# Total length of this replacement string {} replaced with all args	$len{$_} = 0;    }    return bless {	'command' => $commandref,	'seq' => $seq,	'len' => \%len,	'arg_list' => [],	'arg_queue' => $arg_queue,	'max_number_of_args' => $max_number_of_args,	'replacecount' => \%replacecount,	'context_replace' => $context_replace,	'return_files' => $return_files,	'replaced' => undef,    }, ref($class) || $class;}sub seq {    my $self = shift;    return $self->{'seq'};}{    my $max_slot_number;    sub slot {	# Find the number of a free job slot and return it	# Uses:	#   @Global::slots	# Returns:	#   $jobslot = number of jobslot	my $self = shift;	if(not $self->{'slot'}) {	    if(not @Global::slots) {		# $Global::max_slot_number will typically be $Global::max_jobs_running		push @Global::slots, ++$max_slot_number;	    }	    $self->{'slot'} = shift @Global::slots;	}	return $self->{'slot'};    }}sub populate {    # Add arguments from arg_queue until the number of arguments or    # max line length is reached    # Uses:    #   $Global::minimal_command_line_length    #   $opt::cat    #   $opt::fifo    #   $Global::JobQueue    #   $opt::m    #   $opt::X    #   $CommandLine::already_spread    #   $Global::max_jobs_running    # Returns: N/A    my $self = shift;    my $next_arg;    my $max_len = $Global::minimal_command_line_length || Limits::Command::max_length();    if($opt::cat or $opt::fifo) {	# Generate a tempfile name that will be used as {}	my($outfh,$name) = ::tmpfile(SUFFIX => ".pip");	close $outfh;	# Unlink is needed if: ssh otheruser@localhost	unlink $name;	$Global::JobQueue->{'commandlinequeue'}->{'arg_queue'}->unget([Arg->new($name)]);    }    while (not $self->{'arg_queue'}->empty()) {	$next_arg = $self->{'arg_queue'}->get();	if(not defined $next_arg) {	    next;	}	$self->push($next_arg);	if($self->len() >= $max_len) {	    # Command length is now > max_length	    # If there are arguments: remove the last	    # If there are no arguments: Error	    # TODO stuff about -x opt_x	    if($self->number_of_args() > 1) {		# There is something to work on		$self->{'arg_queue'}->unget($self->pop());		last;	    } else {		my $args = join(" ", map { $_->orig() } @$next_arg);		::error("Command line too long (",			$self->len(), " >= ",			$max_len,			") at number ",			$self->{'arg_queue'}->arg_number(),			": ".			(substr($args,0,50))."...\n");		$self->{'arg_queue'}->unget($self->pop());		::wait_and_exit(255);	    }	}	if(defined $self->{'max_number_of_args'}) {	    if($self->number_of_args() >= $self->{'max_number_of_args'}) {		last;	    }	}    }    if(($opt::m or $opt::X) and not $CommandLine::already_spread       and $self->{'arg_queue'}->empty() and $Global::max_jobs_running) {	# -m or -X and EOF => Spread the arguments over all jobslots	# (unless they are already spread)	$CommandLine::already_spread ||= 1;	if($self->number_of_args() > 1) {	    $self->{'max_number_of_args'} =		::ceil($self->number_of_args()/$Global::max_jobs_running);	    $Global::JobQueue->{'commandlinequeue'}->{'max_number_of_args'} =		$self->{'max_number_of_args'};	    $self->{'arg_queue'}->unget($self->pop_all());	    while($self->number_of_args() < $self->{'max_number_of_args'}) {		$self->push($self->{'arg_queue'}->get());	    }	}    }}sub push {    # Add one or more records as arguments    # Returns: N/A    my $self = shift;    my $record = shift;    push @{$self->{'arg_list'}}, $record;    my $quote_arg = $Global::noquote ? 0 : not $Global::quoting;    my $rep;    for my $arg (@$record) {	if(defined $arg) {	    for my $perlexpr (keys %{$self->{'replacecount'}}) {		# 50% faster than below		$self->{'len'}{$perlexpr} += length $arg->replace($perlexpr,$quote_arg,$self);		# $rep = $arg->replace($perlexpr,$quote_arg,$self);		# $self->{'len'}{$perlexpr} += length $rep;		# ::debug("length", "Length: ", length $rep,		# "(", $perlexpr, "=>", $rep, ")\n");	    }	}    }}sub pop {    # Remove last argument    # Returns:    #   the last record    my $self = shift;    my $record = pop @{$self->{'arg_list'}};    my $quote_arg = $Global::noquote ? 0 : not $Global::quoting;    for my $arg (@$record) {	if(defined $arg) {	    for my $perlexpr (keys %{$self->{'replacecount'}}) {		$self->{'len'}{$perlexpr} -=		    length $arg->replace($perlexpr,$quote_arg,$self);	    }	}    }    return $record;}sub pop_all {    # Remove all arguments and zeros the length of replacement strings    # Returns:    #   all records    my $self = shift;    my @popped = @{$self->{'arg_list'}};    for my $replacement_string (keys %{$self->{'replacecount'}}) {	$self->{'len'}{$replacement_string} = 0;    }    $self->{'arg_list'} = [];    return @popped;}sub number_of_args {    # The number of records    # Returns:    #   number of records    my $self = shift;    # Ftq rudef oaawuq ime dqxqmeqp az 2011-01-24 mzp ime iaz nk MQhmd    # Mdzrvadp Nvmdymeaz az 2011-04-10. Ftue oaawuq dqxqmeqp az    # 2013-08-18 ue m nuf tmdpqd me kag tmhq fa geq daf14. Bxqmeq    # qymux oaawuq@fmzsq.pw itqz kag dqmp ftue.    #    # U my ftq ymuzfmuzqd ar m buqoq ar rdqq earfimdq omxxqp SZG    # Bmdmxxqx. Rdqq earfimdq sgmdmzfqqe kag mooqee fa ftq eagdoq    # oapq, ngf U tmhq nqqz iazpqduzs tai ymzk mofgmxxk _dqmp_ ftq    # eagdoq oapq.    #    # Fa fqef ftue U bgf uz m oayyqzf fqxxuzs bqabxq fa qymux yq itqz    # ftqk dqmp ftue. Ftq oayyqzf ime bgf uz m eqofuaz ar ftq oapq    # ftmf za azq iagxp xaaw fa ruj ad uybdahq ftq earfimdq - ea ftq    # eagdoq oapq qcguhmxqzf fa m pgefk oadzqd. Fa ymwq egdq ftq    # oayyqzf iagxp zaf etai gb ur eayq azq vgef sdqbbqp ftdagst ftq    # eagdoq oapq U daf13'qp ftq eagdoq oapq    # tffb://qz.iuwubqpum.ads/iuwu/DAF13    #    # 2.5 yazfte xmfqd U dqoquhqp mz qymux rday eayqazq ita zaf azxk    # ymzmsqp fa ruzp ftq oayyqzf, ngf mxea ymzmsqp fa sgqee ftq oapq    # tmp fa nq daf13'qp.    #    # Ftue nduzse yq fa ftq oazoxgeuaz ftmf ftqdq _mdq_ bqabxq, ita    # mdq zaf mrruxumfqp iuft ftq bdavqof, ftmf iuxx dqmp ftq eagdoq    # oapq - ftagst uf ymk zaf tmbbqz hqdk arfqz.    #    # This is really the number of records    return $#{$self->{'arg_list'}}+1;}sub number_of_recargs {    # The number of args in records    # Returns:    #   number of args records    my $self = shift;    my $sum = 0;    my $nrec = scalar @{$self->{'arg_list'}};    if($nrec) {	$sum = $nrec * (scalar @{$self->{'arg_list'}[0]});    }    return $sum;}sub args_as_string {    # Returns:    #  all unmodified arguments joined with ' ' (similar to {})    my $self = shift;    return (join " ", map { $_->orig() }	    map { @$_ } @{$self->{'arg_list'}});}sub args_as_dirname {    # Returns:    #  all unmodified arguments joined with '/' (similar to {})    #  \t \0 \\ and / are quoted as: \t \0 \\ \_    # If $Global::max_file_length: Keep subdirs < $Global::max_file_length    my $self = shift;    my @res = ();    for my $rec_ref (@{$self->{'arg_list'}}) {	# If headers are used, sort by them.	# Otherwise keep the order from the command line.	my @header_indexes_sorted = header_indexes_sorted($#$rec_ref+1);	for my $n (@header_indexes_sorted) {	    CORE::push(@res,		 $Global::input_source_header{$n},		 map { my $s = $_;		       #  \t \0 \\ and / are quoted as: \t \0 \\ \_		       $s =~ s/\\/\\\\/g;		       $s =~ s/\t/\\t/g;		       $s =~ s/\0/\\0/g;		       $s =~ s:/:\\_:g;		       if($Global::max_file_length) {			   # Keep each subdir shorter than the longest			   # allowed file name			   $s = substr($s,0,$Global::max_file_length);		       }		       $s; }		 $rec_ref->[$n-1]->orig());	}    }    return join "/", @res;}sub header_indexes_sorted {    # Sort headers first by number then by name.    # E.g.: 1a 1b 11a 11b    # Returns:    #  Indexes of %Global::input_source_header sorted    my $max_col = shift;    no warnings 'numeric';    for my $col (1 .. $max_col) {	# Make sure the header is defined. If it is not: use column number	if(not defined $Global::input_source_header{$col}) {	    $Global::input_source_header{$col} = $col;	}    }    my @header_indexes_sorted = sort {	# Sort headers numerically then asciibetically	$Global::input_source_header{$a} <=> $Global::input_source_header{$b}	or	    $Global::input_source_header{$a} cmp $Global::input_source_header{$b}    } 1 .. $max_col;    return @header_indexes_sorted;}sub len {    # Uses:    #   $opt::shellquote    # The length of the command line with args substituted    my $self = shift;    my $len = 0;    # Add length of the original command with no args    # Length of command w/ all replacement args removed    $len += $self->{'len'}{'noncontext'} + @{$self->{'command'}} -1;    ::debug("length", "noncontext + command: $len\n");    my $recargs = $self->number_of_recargs();    if($self->{'context_replace'}) {	# Context is duplicated for each arg	$len += $recargs * $self->{'len'}{'context'};	for my $replstring (keys %{$self->{'replacecount'}}) {	    # If the replacements string is more than once: mulitply its length	    $len += $self->{'len'}{$replstring} *		$self->{'replacecount'}{$replstring};	    ::debug("length", $replstring, " ", $self->{'len'}{$replstring}, "*",		    $self->{'replacecount'}{$replstring}, "\n");	}	# echo 11 22 33 44 55 66 77 88 99 1010	# echo 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10	# 5 +  ctxgrp*arg	::debug("length", "Ctxgrp: ", $self->{'len'}{'contextgroups'},		" Groups: ", $self->{'len'}{'noncontextgroups'}, "\n");	# Add space between context groups	$len += ($recargs-1) * ($self->{'len'}{'contextgroups'});    } else {	# Each replacement string may occur several times	# Add the length for each time	$len += 1*$self->{'len'}{'context'};	::debug("length", "context+noncontext + command: $len\n");	for my $replstring (keys %{$self->{'replacecount'}}) {	    # (space between regargs + length of replacement)	    # * number this replacement is used	    $len += ($recargs -1 + $self->{'len'}{$replstring}) *		$self->{'replacecount'}{$replstring};	}    }    if($opt::nice) {	# Pessimistic length if --nice is set	# Worse than worst case: every char needs to be quoted with \	$len *= 2;    }    if($Global::quoting) {	# Pessimistic length if -q is set	# Worse than worst case: every char needs to be quoted with \	$len *= 2;    }    if($opt::shellquote) {	# Pessimistic length if --shellquote is set	# Worse than worst case: every char needs to be quoted with \ twice	$len *= 4;    }    # If we are using --env, add the prefix for that, too.    $len += $Global::envvarlen;    return $len;}sub replaced {    # Uses:    #   $Global::noquote    #   $Global::quoting    # Returns:    #   $replaced = command with place holders replaced and prepended    my $self = shift;    if(not defined $self->{'replaced'}) {	# Don't quote arguments if the input is the full command line	my $quote_arg = $Global::noquote ? 0 : not $Global::quoting;	$self->{'replaced'} = $self->replace_placeholders($self->{'command'},$Global::quoting,$quote_arg);	my $len = length $self->{'replaced'};	if ($len != $self->len()) {	    ::debug("length", $len, " != ", $self->len(), " ", $self->{'replaced'}, "\n");	} else {	    ::debug("length", $len, " == ", $self->len(), " ", $self->{'replaced'}, "\n");	}    }    return $self->{'replaced'};}sub replace_placeholders {    # Replace foo{}bar with fooargbar    # Input:    #   $targetref = command as shell words    #   $quote = should everything be quoted?    #   $quote_arg = should replaced arguments be quoted?    # Returns:    #   @target with placeholders replaced    my $self = shift;    my $targetref = shift;    my $quote = shift;    my $quote_arg = shift;    my $context_replace = $self->{'context_replace'};    my @target = @$targetref;    ::debug("replace", "Replace @target\n");    # -X = context replace    # maybe multiple input sources    # maybe --xapply    if(not @target) {	# @target is empty: Return empty array	return @target;    }    # Fish out the words that have replacement strings in them    my %word;    for (@target) {	my $tt = $_;	::debug("replace", "Target: $tt");	# a{1}b{}c{}d	# a{=1 $_=$_ =}b{= $_=$_ =}c{= $_=$_ =}d	# a\257<1 $_=$_ \257>b\257< $_=$_ \257>c\257< $_=$_ \257>d	#    A B C => aAbA B CcA B Cd	# -X A B C => aAbAcAd aAbBcBd aAbCcCd	if($context_replace) {	    while($tt =~ s/([^\s\257]*  # before {=                     (?:                      \257<       # {=                      [^\257]*?   # The perl expression                      \257>       # =}                      [^\s\257]*  # after =}                     )+)/ /x) {		# $1 = pre \257 perlexpr \257 post		$word{"$1"} ||= 1;	    }	} else {	    while($tt =~ s/( (?: \257<([^\257]*?)\257>) )//x) {		# $f = \257 perlexpr \257		$word{$1} ||= 1;	    }	}    }    my @word = keys %word;    my %replace;    my @arg;    for my $record (@{$self->{'arg_list'}}) {	# $self->{'arg_list'} = [ [Arg11, Arg12], [Arg21, Arg22], [Arg31, Arg32] ]	# Merge arg-objects from records into @arg for easy access	CORE::push @arg, @$record;    }    # Add one arg if empty to allow {#} and {%} to be computed only once    if(not @arg) { @arg = (Arg->new("")); }    # Number of arguments - used for positional arguments    my $n = $#_+1;    # This is actually a CommandLine-object,    # but it looks nice to be able to say {= $job->slot() =}    my $job = $self;    for my $word (@word) {	# word = AB \257< perlexpr \257> CD \257< perlexpr \257> EF	my $w = $word;	::debug("replace", "Replacing in $w\n");	# Replace positional arguments	$w =~ s< ([^\s\257]*)  # before {=                 \257<         # {=                 (-?\d+)       # Position (eg. -2 or 3)                 ([^\257]*?)   # The perl expression                 \257>         # =}                 ([^\s\257]*)  # after =}               >	   { $1. # Context (pre)		 (		 $arg[$2 > 0 ? $2-1 : $n+$2] ? # If defined: replace		 $arg[$2 > 0 ? $2-1 : $n+$2]->replace($3,$quote_arg,$self)		 : "")		 .$4 }egx;# Context (post)	::debug("replace", "Positional replaced $word with: $w\n");	if($w !~ /\257/) {	    # No more replacement strings in $w: No need to do more	    if($quote) {		CORE::push(@{$replace{::shell_quote($word)}}, $w);	    } else {		CORE::push(@{$replace{$word}}, $w);	    }	    next;	}	# for each arg:	#   compute replacement for each string	#   replace replacement strings with replacement in the word value	#   push to replace word value	::debug("replace", "Positional done: $w\n");	for my $arg (@arg) {	    my $val = $w;	    my $number_of_replacements = 0;	    for my $perlexpr (keys %{$self->{'replacecount'}}) {		# Replace {= perl expr =} with value for each arg		$number_of_replacements +=		    $val =~ s{\257<\Q$perlexpr\E\257>}		{$arg ? $arg->replace($perlexpr,$quote_arg,$self) : ""}eg;	    }	    my $ww = $word;	    if($quote) {		$ww = ::shell_quote_scalar($word);		$val = ::shell_quote_scalar($val);	    }	    if($number_of_replacements) {		CORE::push(@{$replace{$ww}}, $val);	    }	}    }    if($quote) {	@target = ::shell_quote(@target);    }    # ::debug("replace", "%replace=",::my_dump(%replace),"\n");    if(%replace) {	# Substitute the replace strings with the replacement values	# Must be sorted by length if a short word is a substring of a long word	my $regexp = join('|', map { my $s = $_; $s =~ s/(\W)/\\$1/g; $s }			  sort { length $b <=> length $a } keys %replace);	for(@target) {	    s/($regexp)/join(" ",@{$replace{$1}})/ge;	}    }    ::debug("replace", "Return @target\n");    return wantarray ? @target : "@target";}package CommandLineQueue;sub new {    my $class = shift;    my $commandref = shift;    my $read_from = shift;    my $context_replace = shift;    my $max_number_of_args = shift;    my $return_files = shift;    my @unget = ();    my ($count,%replacecount,$posrpl,$perlexpr,%len);    my @command = @$commandref;    # If the first command start with '-' it is probably an option    if($command[0] =~ /^\s*(-\S+)/) {	# Is this really a command in $PATH starting with '-'?	my $cmd = $1;	if(not ::which($cmd)) {	    ::error("Command ($cmd) starts with '-'. Is this a wrong option?\n");	    ::wait_and_exit(255);	}    }    # Replace replacement strings with {= perl expr =}    # Protect matching inside {= perl expr =}    # by replacing {= and =} with \257< and \257>    for(@command) {	if(/\257/) {	    ::error("Command cannot contain the character \257. Use a function for that.\n");	    ::wait_and_exit(255);	}	s/\Q$Global::parensleft\E(.*?)\Q$Global::parensright\E/\257<$1\257>/gx;    }    for my $rpl (keys %Global::rpl) {	# Replace the short hand string with the {= perl expr =} in $command and $opt::tagstring	# Avoid replacing inside existing {= perl expr =}	for(@command,@Global::ret_files) {	    while(s/((^|\257>)[^\257]*?) # Don't replace after \257 unless \257>                  \Q$rpl\E/$1\257<$Global::rpl{$rpl}\257>/xg) {	    }	}	if(defined $opt::tagstring) {	    for($opt::tagstring) {		while(s/((^|\257>)[^\257]*?) # Don't replace after \257 unless \257>                      \Q$rpl\E/$1\257<$Global::rpl{$rpl}\257>/x) {}	    }	}	# Do the same for the positional replacement strings	# A bit harder as we have to put in the position number	$posrpl = $rpl;	if($posrpl =~ s/^\{//) {	    # Only do this if the shorthand start with {	    for(@command,@Global::ret_files) {		s/\{(-?\d+)\Q$posrpl\E/\257<$1 $Global::rpl{$rpl}\257>/g;	    }	    if(defined $opt::tagstring) {		$opt::tagstring =~ s/\{(-?\d+)\Q$posrpl\E/\257<$1 $perlexpr\257>/g;	    }	}    }    my $sum = 0;    while($sum == 0) {	# Count how many times each replacement string is used	my @cmd = @command;	my $contextlen = 0;	my $noncontextlen = 0;	my $contextgroups = 0;	for my $c (@cmd) {	    while($c =~ s/ \257<([^\257]*?)\257> /\000/x) {		# %replacecount = { "perlexpr" => number of times seen }		# e.g { "$_++" => 2 }		$replacecount{$1} ++;		$sum++;	    }	    # Measure the length of the context around the {= perl expr =}	    # Use that {=...=} has been replaced with \000 above	    # So there is no need to deal with \257<	    while($c =~ s/ (\S*\000\S*) //x) {		my $w = $1;		$w =~ tr/\000//d; # Remove all \000's		$contextlen += length($w);		$contextgroups++;	    }	    # All {= perl expr =} have been removed: The rest is non-context	    $noncontextlen += length $c;	}	if($opt::tagstring) {	    my $t = $opt::tagstring;	    while($t =~ s/ \257<([^\257]*)\257> //x) {		# %replacecount = { "perlexpr" => number of times seen }		# e.g { "$_++" => 2 }		# But for tagstring we just need to mark it as seen		$replacecount{$1}||=1;	    }	}	$len{'context'} = 0+$contextlen;	$len{'noncontext'} = $noncontextlen;	$len{'contextgroups'} = $contextgroups;	$len{'noncontextgroups'} = @cmd-$contextgroups;	::debug("length", "@command Context: ", $len{'context'},		" Non: ", $len{'noncontext'}, " Ctxgrp: ", $len{'contextgroups'},		" NonCtxGrp: ", $len{'noncontextgroups'}, "\n");	if($sum == 0) {	    # Default command = {}	    # If not replacement string: append {}	    if(not @command) {		@command = ("\257<\257>");		$Global::noquote = 1;	    } elsif(($opt::pipe or $opt::pipepart)		    and not $opt::fifo and not $opt::cat) {		# With --pipe / --pipe-part you can have no replacement		last;	    } else {		# Append {} to the command if there are no {...}'s and no {=...=}		push @command, ("\257<\257>");	    }	}    }    return bless {	'unget' => \@unget,	'command' => \@command,	'replacecount' => \%replacecount,	'arg_queue' => RecordQueue->new($read_from,$opt::colsep),	'context_replace' => $context_replace,	'len' => \%len,	'max_number_of_args' => $max_number_of_args,	'size' => undef,	'return_files' => $return_files,	'seq' => 1,    }, ref($class) || $class;}sub get {    my $self = shift;    if(@{$self->{'unget'}}) {	my $cmd_line = shift @{$self->{'unget'}};	return ($cmd_line);    } else {	my $cmd_line;	$cmd_line = CommandLine->new($self->seq(),				     $self->{'command'},				     $self->{'arg_queue'},				     $self->{'context_replace'},				     $self->{'max_number_of_args'},				     $self->{'return_files'},				     $self->{'replacecount'},				     $self->{'len'},	    );	$cmd_line->populate();	::debug("init","cmd_line->number_of_args ",		$cmd_line->number_of_args(), "\n");	if($opt::pipe or $opt::pipepart) {	    if($cmd_line->replaced() eq "") {		# Empty command - pipe requires a command		::error("--pipe must have a command to pipe into (e.g. 'cat').\n");		::wait_and_exit(255);	    }	} else {	    if($cmd_line->number_of_args() == 0) {		# We did not get more args - maybe at EOF string?		return undef;	    } elsif($cmd_line->replaced() eq "") {		# Empty command - get the next instead		return $self->get();	    }	}	$self->set_seq($self->seq()+1);	return $cmd_line;    }}sub unget {    my $self = shift;    unshift @{$self->{'unget'}}, @_;}sub empty {    my $self = shift;    my $empty = (not @{$self->{'unget'}}) && $self->{'arg_queue'}->empty();    ::debug("run", "CommandLineQueue->empty $empty");    return $empty;}sub seq {    my $self = shift;    return $self->{'seq'};}sub set_seq {    my $self = shift;    $self->{'seq'} = shift;}sub quote_args {    my $self = shift;    # If there is not command emulate |bash    return $self->{'command'};}sub size {    my $self = shift;    if(not $self->{'size'}) {	my @all_lines = ();	while(not $self->{'arg_queue'}->empty()) {	    push @all_lines, CommandLine->new($self->{'command'},					      $self->{'arg_queue'},					      $self->{'context_replace'},					      $self->{'max_number_of_args'});	}	$self->{'size'} = @all_lines;	$self->unget(@all_lines);    }    return $self->{'size'};}package Limits::Command;# Maximal command line length (for -m and -X)sub max_length {    # Find the max_length of a command line and cache it    # Returns:    #   number of chars on the longest command line allowed    if(not $Limits::Command::line_max_len) {	# Disk cache of max command line length	my $len_cache = $ENV{'HOME'} . "/.parallel/tmp/linelen-" . ::hostname();	my $cached_limit;	if(-e $len_cache) {	    open(my $fh, "<", $len_cache) || ::die_bug("Cannot read $len_cache");	    $cached_limit = <$fh>;	    close $fh;	} else {	    $cached_limit = real_max_length();	    # If $HOME is write protected: Do not fail	    mkdir($ENV{'HOME'} . "/.parallel");	    mkdir($ENV{'HOME'} . "/.parallel/tmp");	    open(my $fh, ">", $len_cache);	    print $fh $cached_limit;	    close $fh;	}	$Limits::Command::line_max_len = $cached_limit;	if($opt::max_chars) {	    if($opt::max_chars <= $cached_limit) {		$Limits::Command::line_max_len = $opt::max_chars;	    } else {		::warning("Value for -s option ",			  "should be < $cached_limit.\n");	    }	}    }    return $Limits::Command::line_max_len;}sub real_max_length {    # Find the max_length of a command line    # Returns:    #   The maximal command line length    # Use an upper bound of 8 MB if the shell allows for for infinite long lengths    my $upper = 8_000_000;    my $len = 8;    do {	if($len > $upper) { return $len };	$len *= 16;    } while (is_acceptable_command_line_length($len));    # Then search for the actual max length between 0 and upper bound    return binary_find_max_length(int($len/16),$len);}sub binary_find_max_length {    # Given a lower and upper bound find the max_length of a command line    # Returns:    #   number of chars on the longest command line allowed    my ($lower, $upper) = (@_);    if($lower == $upper or $lower == $upper-1) { return $lower; }    my $middle = int (($upper-$lower)/2 + $lower);    ::debug("init", "Maxlen: $lower,$upper,$middle : ");    if (is_acceptable_command_line_length($middle)) {	return binary_find_max_length($middle,$upper);    } else {	return binary_find_max_length($lower,$middle);    }}sub is_acceptable_command_line_length {    # Test if a command line of this length can run    # Returns:    #   0 if the command line length is too long    #   1 otherwise    my $len = shift;    local *STDERR;    open (STDERR, ">", "/dev/null");    system "true "."x"x$len;    close STDERR;    ::debug("init", "$len=$? ");    return not $?;}package RecordQueue;sub new {    my $class = shift;    my $fhs = shift;    my $colsep = shift;    my @unget = ();    my $arg_sub_queue;    if($colsep) {	# Open one file with colsep	$arg_sub_queue = RecordColQueue->new($fhs);    } else {	# Open one or more files if multiple -a	$arg_sub_queue = MultifileQueue->new($fhs);    }    return bless {	'unget' => \@unget,	'arg_number' => 0,	'arg_sub_queue' => $arg_sub_queue,    }, ref($class) || $class;}sub get {    # Returns:    #   reference to array of Arg-objects    my $self = shift;    if(@{$self->{'unget'}}) {	$self->{'arg_number'}++;	return shift @{$self->{'unget'}};    }    my $ret = $self->{'arg_sub_queue'}->get();    if(defined $Global::max_number_of_args       and $Global::max_number_of_args == 0) {	::debug("run", "Read 1 but return 0 args\n");	return [Arg->new("")];    } else {	return $ret;    }}sub unget {    my $self = shift;    ::debug("run", "RecordQueue-unget '@_'\n");    $self->{'arg_number'} -= @_;    unshift @{$self->{'unget'}}, @_;}sub empty {    my $self = shift;    my $empty = not @{$self->{'unget'}};    $empty &&= $self->{'arg_sub_queue'}->empty();    ::debug("run", "RecordQueue->empty $empty");    return $empty;}sub arg_number {    my $self = shift;    return $self->{'arg_number'};}package RecordColQueue;sub new {    my $class = shift;    my $fhs = shift;    my @unget = ();    my $arg_sub_queue = MultifileQueue->new($fhs);    return bless {	'unget' => \@unget,	'arg_sub_queue' => $arg_sub_queue,    }, ref($class) || $class;}sub get {    # Returns:    #   reference to array of Arg-objects    my $self = shift;    if(@{$self->{'unget'}}) {	return shift @{$self->{'unget'}};    }    my $unget_ref=$self->{'unget'};    if($self->{'arg_sub_queue'}->empty()) {	return undef;    }    my $in_record = $self->{'arg_sub_queue'}->get();    if(defined $in_record) {	my @out_record = ();	for my $arg (@$in_record) {	    ::debug("run", "RecordColQueue::arg $arg\n");	    my $line = $arg->orig();	    ::debug("run", "line='$line'\n");	    if($line ne "") {		for my $s (split /$opt::colsep/o, $line, -1) {		    push @out_record, Arg->new($s);		}	    } else {		push @out_record, Arg->new("");	    }	}	return \@out_record;    } else {	return undef;    }}sub unget {    my $self = shift;    ::debug("run", "RecordColQueue-unget '@_'\n");    unshift @{$self->{'unget'}}, @_;}sub empty {    my $self = shift;    my $empty = (not @{$self->{'unget'}} and $self->{'arg_sub_queue'}->empty());    ::debug("run", "RecordColQueue->empty $empty");    return $empty;}package MultifileQueue;@Global::unget_argv=();sub new {    my $class = shift;    my $fhs = shift;    for my $fh (@$fhs) {	if(-t $fh) {	    ::warning("Input is read from the terminal. ".		      "Only experts do this on purpose. ".		      "Press CTRL-D to exit.\n");	}    }    return bless {	'unget' => \@Global::unget_argv,	'fhs' => $fhs,	'arg_matrix' => undef,    }, ref($class) || $class;}sub get {    my $self = shift;    if($opt::xapply) {	return $self->xapply_get();    } else {	return $self->nest_get();    }}sub unget {    my $self = shift;    ::debug("run", "MultifileQueue-unget '@_'\n");    unshift @{$self->{'unget'}}, @_;}sub empty {    my $self = shift;    my $empty = (not @Global::unget_argv		 and not @{$self->{'unget'}});    for my $fh (@{$self->{'fhs'}}) {	$empty &&= eof($fh);    }    ::debug("run", "MultifileQueue->empty $empty ");    return $empty;}sub xapply_get {    my $self = shift;    if(@{$self->{'unget'}}) {	return shift @{$self->{'unget'}};    }    my @record = ();    my $prepend = undef;    my $empty = 1;    for my $fh (@{$self->{'fhs'}}) {	my $arg = read_arg_from_fh($fh);	if(defined $arg) {	    # Record $arg for recycling at end of file	    push @{$self->{'arg_matrix'}{$fh}}, $arg;	    push @record, $arg;	    $empty = 0;	} else {	    ::debug("run", "EOA ");	    # End of file: Recycle arguments	    push @{$self->{'arg_matrix'}{$fh}}, shift @{$self->{'arg_matrix'}{$fh}};	    # return last @{$args->{'args'}{$fh}};	    push @record, @{$self->{'arg_matrix'}{$fh}}[-1];	}    }    if($empty) {	return undef;    } else {	return \@record;    }}sub nest_get {    my $self = shift;    if(@{$self->{'unget'}}) {	return shift @{$self->{'unget'}};    }    my @record = ();    my $prepend = undef;    my $empty = 1;    my $no_of_inputsources = $#{$self->{'fhs'}} + 1;    if(not $self->{'arg_matrix'}) {	# Initialize @arg_matrix with one arg from each file	# read one line from each file	my @first_arg_set;	my $all_empty = 1;	for (my $fhno = 0; $fhno < $no_of_inputsources ; $fhno++) {	    my $arg = read_arg_from_fh($self->{'fhs'}[$fhno]);	    if(defined $arg) {		$all_empty = 0;	    }	    $self->{'arg_matrix'}[$fhno][0] = $arg || Arg->new("");	    push @first_arg_set, $self->{'arg_matrix'}[$fhno][0];	}	if($all_empty) {	    # All filehandles were at eof or eof-string	    return undef;	}	return [@first_arg_set];    }    # Treat the case with one input source special.  For multiple    # input sources we need to remember all previously read values to    # generate all combinations. But for one input source we can    # forget the value after first use.    if($no_of_inputsources == 1) {	my $arg = read_arg_from_fh($self->{'fhs'}[0]);	if(defined($arg)) {	    return [$arg];	}	return undef;    }    for (my $fhno = $no_of_inputsources - 1; $fhno >= 0; $fhno--) {	if(eof($self->{'fhs'}[$fhno])) {	    next;	} else {	    # read one	    my $arg = read_arg_from_fh($self->{'fhs'}[$fhno]);	    defined($arg) || next; # If we just read an EOF string: Treat this as EOF	    my $len = $#{$self->{'arg_matrix'}[$fhno]} + 1;	    $self->{'arg_matrix'}[$fhno][$len] = $arg;	    # make all new combinations	    my @combarg = ();	    for (my $fhn = 0; $fhn < $no_of_inputsources; $fhn++) {		push @combarg, [0, $#{$self->{'arg_matrix'}[$fhn]}];	    }	    $combarg[$fhno] = [$len,$len]; # Find only combinations with this new entry	    # map combinations	    # [ 1, 3, 7 ], [ 2, 4, 1 ]	    # =>	    # [ m[0][1], m[1][3], m[3][7] ], [ m[0][2], m[1][4], m[2][1] ]	    my @mapped;	    for my $c (expand_combinations(@combarg)) {		my @a;		for my $n (0 .. $no_of_inputsources - 1 ) {		    push @a,  $self->{'arg_matrix'}[$n][$$c[$n]];		}		push @mapped, \@a;	    }	    # append the mapped to the ungotten arguments	    push @{$self->{'unget'}}, @mapped;	    # get the first	    return shift @{$self->{'unget'}};	}    }    # all are eof or at EOF string; return from the unget queue    return shift @{$self->{'unget'}};}sub read_arg_from_fh {    # Read one Arg from filehandle    # Returns:    #   Arg-object with one read line    #   undef if end of file    my $fh = shift;    my $prepend = undef;    my $arg;    do {{	# This makes 10% faster	if(not ($arg = <$fh>)) {	    if(defined $prepend) {		return Arg->new($prepend);	    } else {		return undef;	    }	}#	::debug("run", "read $arg\n");	# Remove delimiter	$arg =~ s:$/$::;	if($Global::end_of_file_string and	   $arg eq $Global::end_of_file_string) {	    # Ignore the rest of input file	    close $fh;	    ::debug("run", "EOF-string ($arg) met\n");	    if(defined $prepend) {		return Arg->new($prepend);	    } else {		return undef;	    }	}	if(defined $prepend) {	    $arg = $prepend.$arg; # For line continuation	    $prepend = undef; #undef;	}	if($Global::ignore_empty) {	    if($arg =~ /^\s*$/) {		redo; # Try the next line	    }	}	if($Global::max_lines) {	    if($arg =~ /\s$/) {		# Trailing space => continued on next line		$prepend = $arg;		redo;	    }	}    }} while (1 == 0); # Dummy loop {{}} for redo    if(defined $arg) {	return Arg->new($arg);    } else {	::die_bug("multiread arg undefined");    }}sub expand_combinations {    # Input:    #   ([xmin,xmax], [ymin,ymax], ...)    # Returns: ([x,y,...],[x,y,...])    # where xmin <= x <= xmax and ymin <= y <= ymax    my $minmax_ref = shift;    my $xmin = $$minmax_ref[0];    my $xmax = $$minmax_ref[1];    my @p;    if(@_) {	# If there are more columns: Compute those recursively	my @rest = expand_combinations(@_);	for(my $x = $xmin; $x <= $xmax; $x++) {	    push @p, map { [$x, @$_] } @rest;	}    } else {	for(my $x = $xmin; $x <= $xmax; $x++) {	    push @p, [$x];	}    }    return @p;}package Arg;sub new {    my $class = shift;    my $orig = shift;    my @hostgroups;    if($opt::hostgroups) {	if($orig =~ s:@(.+)::) {	    # We found hostgroups on the arg	    @hostgroups = split(/\+/, $1);	    if(not grep { defined $Global::hostgroups{$_} } @hostgroups) {		::warning("No such hostgroup (@hostgroups)\n");		@hostgroups = (keys %Global::hostgroups);	    }        } else {	    @hostgroups = (keys %Global::hostgroups);	}    }    return bless {	'orig' => $orig,	'hostgroups' => \@hostgroups,    }, ref($class) || $class;}sub replace {    # Calculates the corresponding value for a given perl expression    # Returns:    #   The calculated string (quoted if asked for)    my $self = shift;    my $perlexpr = shift; # E.g. $_=$_ or s/.gz//    my $quote = (shift) ? 1 : 0; # should the string be quoted?    # This is actually a CommandLine-object,    # but it looks nice to be able to say {= $job->slot() =}    my $job = shift;    $perlexpr =~ s/^-?\d+ //; # Positional replace treated as normal replace    if(not defined $self->{"rpl",0,$perlexpr}) {	local $_;	if($Global::trim eq "n") {	    $_ = $self->{'orig'};	} else {	    $_ = trim_of($self->{'orig'});	}	::debug("replace", "eval ", $perlexpr, " ", $_, "\n");	if(not $Global::perleval{$perlexpr}) {	    # Make an anonymous function of the $perlexpr	    # And more importantly: Compile it only once	    if($Global::perleval{$perlexpr} =	       eval('sub { no strict; no warnings; my $job = shift; '.		    $perlexpr.' }')) {		# All is good	    } else {		# The eval failed. Maybe $perlexpr is invalid perl?		::error("Cannot use $perlexpr: $@\n");		::wait_and_exit(255);	    }	}	# Execute the function	$Global::perleval{$perlexpr}->($job);	$self->{"rpl",0,$perlexpr} = $_;    }    if(not defined $self->{"rpl",$quote,$perlexpr}) {	$self->{"rpl",1,$perlexpr} =	    ::shell_quote_scalar($self->{"rpl",0,$perlexpr});    }    return $self->{"rpl",$quote,$perlexpr};}sub orig {    my $self = shift;    return $self->{'orig'};}sub trim_of {    # Removes white space as specifed by --trim:    # n = nothing    # l = start    # r = end    # lr|rl = both    # Returns:    #   string with white space removed as needed    my @strings = map { defined $_ ? $_ : "" } (@_);    my $arg;    if($Global::trim eq "n") {	# skip    } elsif($Global::trim eq "l") {	for my $arg (@strings) { $arg =~ s/^\s+//; }    } elsif($Global::trim eq "r") {	for my $arg (@strings) { $arg =~ s/\s+$//; }    } elsif($Global::trim eq "rl" or $Global::trim eq "lr") {	for my $arg (@strings) { $arg =~ s/^\s+//; $arg =~ s/\s+$//; }    } else {	::error("--trim must be one of: r l rl lr.\n");	::wait_and_exit(255);    }    return wantarray ? @strings : "@strings";}package TimeoutQueue;sub new {    my $class = shift;    my $delta_time = shift;    my ($pct);    if($delta_time =~ /(\d+(\.\d+)?)%/) {	# Timeout in percent	$pct = $1/100;	$delta_time = 1_000_000;    }    return bless {	'queue' => [],	'delta_time' => $delta_time,	'pct' => $pct,	'remedian_idx' => 0,	'remedian_arr' => [],	'remedian' => undef,    }, ref($class) || $class;}sub delta_time {    my $self = shift;    return $self->{'delta_time'};}sub set_delta_time {    my $self = shift;    $self->{'delta_time'} = shift;}sub remedian {    my $self = shift;    return $self->{'remedian'};}sub set_remedian {    # Set median of the last 999^3 (=997002999) values using Remedian    #    # Rousseeuw, Peter J., and Gilbert W. Bassett Jr. "The remedian: A    # robust averaging method for large data sets." Journal of the    # American Statistical Association 85.409 (1990): 97-104.    my $self = shift;    my $val = shift;    my $i = $self->{'remedian_idx'}++;    my $rref = $self->{'remedian_arr'};    $rref->[0][$i%999] = $val;    $rref->[1][$i/999%999] = (sort @{$rref->[0]})[$#{$rref->[0]}/2];    $rref->[2][$i/999/999%999] = (sort @{$rref->[1]})[$#{$rref->[1]}/2];    $self->{'remedian'} = (sort @{$rref->[2]})[$#{$rref->[2]}/2];}sub update_delta_time {    # Update delta_time based on runtime of finished job if timeout is    # a percentage    my $self = shift;    my $runtime = shift;    if($self->{'pct'}) {	$self->set_remedian($runtime);	$self->{'delta_time'} = $self->{'pct'} * $self->remedian();	::debug("run", "Timeout: $self->{'delta_time'}s ");    }}sub process_timeouts {    # Check if there was a timeout    my $self = shift;    # $self->{'queue'} is sorted by start time    while (@{$self->{'queue'}}) {	my $job = $self->{'queue'}[0];	if($job->endtime()) {	    # Job already finished. No need to timeout the job	    # This could be because of --keep-order	    shift @{$self->{'queue'}};	} elsif($job->timedout($self->{'delta_time'})) {	    # Need to shift off queue before kill	    # because kill calls usleep that calls process_timeouts	    shift @{$self->{'queue'}};	    $job->kill();	} else {	    # Because they are sorted by start time the rest are later	    last;	}    }}sub insert {    my $self = shift;    my $in = shift;    push @{$self->{'queue'}}, $in;}package Semaphore;# This package provides a counting semaphore## If a process dies without releasing the semaphore the next process# that needs that entry will clean up dead semaphores## The semaphores are stored in ~/.parallel/semaphores/id-<name> Each# file in ~/.parallel/semaphores/id-<name>/ is the process ID of the# process holding the entry. If the process dies, the entry can be# taken by another process.sub new {    my $class = shift;    my $id = shift;    my $count = shift;    $id=~s/([^-_a-z0-9])/unpack("H*",$1)/ige; # Convert non-word chars to hex    $id="id-".$id; # To distinguish it from a process id    my $parallel_dir = $ENV{'HOME'}."/.parallel";    -d $parallel_dir or mkdir_or_die($parallel_dir);    my $parallel_locks = $parallel_dir."/semaphores";    -d $parallel_locks or mkdir_or_die($parallel_locks);    my $lockdir = "$parallel_locks/$id";    my $lockfile = $lockdir.".lock";    if($count < 1) { ::die_bug("semaphore-count: $count"); }    return bless {	'lockfile' => $lockfile,	'lockfh' => Symbol::gensym(),	'lockdir' => $lockdir,	'id' => $id,	'idfile' => $lockdir."/".$id,	'pid' => $$,	'pidfile' => $lockdir."/".$$.'@'.::hostname(),	'count' => $count + 1 # nlinks returns a link for the 'id-' as well    }, ref($class) || $class;}sub acquire {    my $self = shift;    my $sleep = 1; # 1 ms    my $start_time = time;    while(1) {	$self->atomic_link_if_count_less_than() and last;	::debug("sem", "Remove dead locks");	my $lockdir = $self->{'lockdir'};	for my $d (glob "$lockdir/*") {	    ::debug("sem", "Lock $d $lockdir\n");	    $d =~ m:$lockdir/([0-9]+)\@([-\._a-z0-9]+)$:o or next;	    my ($pid, $host) = ($1, $2);	    if($host eq ::hostname()) {		if(not kill 0, $1) {		    ::debug("sem", "Dead: $d");		    unlink $d;		} else {		    ::debug("sem", "Alive: $d");		}	    }	}	# try again	$self->atomic_link_if_count_less_than() and last;	# Retry slower and slower up to 1 second	$sleep = ($sleep < 1000) ? ($sleep * 1.1) : ($sleep);	# Random to avoid every sleeping job waking up at the same time	::usleep(rand()*$sleep);	if(defined($opt::timeout) and	   $start_time + $opt::timeout > time) {	    # Acquire the lock anyway	    if(not -e $self->{'idfile'}) {		open (my $fh, ">", $self->{'idfile'}) or		    ::die_bug("timeout_write_idfile: $self->{'idfile'}");		close $fh;	    }	    link $self->{'idfile'}, $self->{'pidfile'};	    last;	}    }    ::debug("sem", "acquired $self->{'pid'}\n");}sub release {    my $self = shift;    unlink $self->{'pidfile'};    if($self->nlinks() == 1) {	# This is the last link, so atomic cleanup	$self->lock();	if($self->nlinks() == 1) {	    unlink $self->{'idfile'};	    rmdir $self->{'lockdir'};	}	$self->unlock();    }    ::debug("run", "released $self->{'pid'}\n");}sub _release {    my $self = shift;    unlink $self->{'pidfile'};    $self->lock();    my $nlinks = $self->nlinks();    ::debug("sem", $nlinks, "<", $self->{'count'});    if($nlinks-- > 1) {       unlink $self->{'idfile'};       open (my $fh, ">", $self->{'idfile'}) or           ::die_bug("write_idfile: $self->{'idfile'}");       print $fh "#"x$nlinks;       close $fh;    } else {       unlink $self->{'idfile'};       rmdir $self->{'lockdir'};    }    $self->unlock();    ::debug("sem", "released $self->{'pid'}\n");}sub atomic_link_if_count_less_than {    # Link $file1 to $file2 if nlinks to $file1 < $count    my $self = shift;    my $retval = 0;    $self->lock();    ::debug($self->nlinks(), "<", $self->{'count'});    if($self->nlinks() < $self->{'count'}) {	-d $self->{'lockdir'} or mkdir_or_die($self->{'lockdir'});	if(not -e $self->{'idfile'}) {	    open (my $fh, ">", $self->{'idfile'}) or		::die_bug("write_idfile: $self->{'idfile'}");	    close $fh;	}	$retval = link $self->{'idfile'}, $self->{'pidfile'};    }    $self->unlock();    ::debug("run", "atomic $retval");    return $retval;}sub _atomic_link_if_count_less_than {    # Link $file1 to $file2 if nlinks to $file1 < $count    my $self = shift;    my $retval = 0;    $self->lock();    my $nlinks = $self->nlinks();    ::debug("sem", $nlinks, "<", $self->{'count'});    if($nlinks++ < $self->{'count'}) {	-d $self->{'lockdir'} or mkdir_or_die($self->{'lockdir'});	if(not -e $self->{'idfile'}) {	    open (my $fh, ">", $self->{'idfile'}) or		::die_bug("write_idfile: $self->{'idfile'}");	    close $fh;	}	open (my $fh, ">", $self->{'idfile'}) or	    ::die_bug("write_idfile: $self->{'idfile'}");	print $fh "#"x$nlinks;	close $fh;	$retval = link $self->{'idfile'}, $self->{'pidfile'};    }    $self->unlock();    ::debug("sem", "atomic $retval");    return $retval;}sub nlinks {    my $self = shift;    if(-e $self->{'idfile'}) {	::debug("sem", "nlinks", (stat(_))[3], "size", (stat(_))[7], "\n");	return (stat(_))[3];    } else {	return 0;    }}sub lock {    my $self = shift;    my $sleep = 100; # 100 ms    my $total_sleep = 0;    $Global::use{"Fcntl"} ||= eval "use Fcntl qw(:DEFAULT :flock); 1;";    my $locked = 0;    while(not $locked) {	if(tell($self->{'lockfh'}) == -1) {	    # File not open	    open($self->{'lockfh'}, ">", $self->{'lockfile'})		or ::debug("run", "Cannot open $self->{'lockfile'}");	}	if($self->{'lockfh'}) {	    # File is open	    chmod 0666, $self->{'lockfile'}; # assuming you want it a+rw	    if(flock($self->{'lockfh'}, LOCK_EX()|LOCK_NB())) {		# The file is locked: No need to retry		$locked = 1;		last;	    } else {		if ($! =~ m/Function not implemented/) {		    ::warning("flock: $!");		    ::warning("Will wait for a random while\n");		    ::usleep(rand(5000));		    # File cannot be locked: No need to retry		    $locked = 2;		    last;		}	    }	}	# Locking failed in first round	# Sleep and try again	$sleep = ($sleep < 1000) ? ($sleep * 1.1) : ($sleep);	# Random to avoid every sleeping job waking up at the same time	::usleep(rand()*$sleep);	$total_sleep += $sleep;	if($opt::semaphoretimeout) {	    if($total_sleep/1000 > $opt::semaphoretimeout) {		# Timeout: bail out		::warning("Semaphore timed out. Ignoring timeout.");		$locked = 3;		last;	    }	} else {	    if($total_sleep/1000 > 30) {		::warning("Semaphore stuck for 30 seconds. Consider using --semaphoretimeout.");	    }	}    }    ::debug("run", "locked $self->{'lockfile'}");}sub unlock {    my $self = shift;    unlink $self->{'lockfile'};    close $self->{'lockfh'};    ::debug("run", "unlocked\n");}sub mkdir_or_die {    # If dir is not writable: die    my $dir = shift;    my @dir_parts = split(m:/:,$dir);    my ($ddir,$part);    while(defined ($part = shift @dir_parts)) {	$part eq "" and next;	$ddir .= "/".$part;	-d $ddir and next;	mkdir $ddir;    }    if(not -w $dir) {	::error("Cannot write to $dir: $!\n");	::wait_and_exit(255);    }}# Keep perl -w happy$opt::x = $Semaphore::timeout = $Semaphore::wait =$Job::file_descriptor_warning_printed = 0;
 |