diff --git a/contrib/python/.gitignore b/contrib/python/.gitignore new file mode 100644 index 0000000..ef8f685 --- /dev/null +++ b/contrib/python/.gitignore @@ -0,0 +1,3 @@ +build/ +dist/ +moth.egg-info diff --git a/contrib/python/MANIFEST.in b/contrib/python/MANIFEST.in new file mode 100644 index 0000000..286c9ba --- /dev/null +++ b/contrib/python/MANIFEST.in @@ -0,0 +1 @@ +include moth/answer_words.txt diff --git a/contrib/python/VERSION b/contrib/python/VERSION new file mode 100644 index 0000000..72536b0 --- /dev/null +++ b/contrib/python/VERSION @@ -0,0 +1 @@ +4.0rc1 diff --git a/contrib/python/moth/__init__.py b/contrib/python/moth/__init__.py new file mode 100644 index 0000000..28a0491 --- /dev/null +++ b/contrib/python/moth/__init__.py @@ -0,0 +1 @@ +from .moth import * diff --git a/contrib/python/moth/answer_words.txt b/contrib/python/moth/answer_words.txt new file mode 100644 index 0000000..7adc1a8 --- /dev/null +++ b/contrib/python/moth/answer_words.txt @@ -0,0 +1,7713 @@ +about +search +other +information +which +their +there +contact +business +online +first +would +services +these +click +service +price +people +state +email +health +world +products +music +should +product +system +policy +number +please +available +copyright +support +message +after +software +video +where +rights +public +books +school +through +links +review +years +order +privacy +items +company +group +under +general +research +university +january +reviews +program +games +management +could +great +united +hotel +international +center +store +travel +comments +development +report +member +details +terms +before +hotels +right +because +local +those +using +results +office +education +national +design +posted +internet +address +community +within +states +phone +shipping +reserved +subject +between +forum +family +based +black +check +special +prices +website +index +being +women +today +technology +south +project +pages +version +section +found +sports +house +related +security +county +american +photo +members +power +while +network +computer +systems +three +total +place +following +download +without +access +think +north +resources +current +posts +media +control +water +history +pictures +personal +since +including +guide +directory +board +location +change +white +small +rating +government +children +during +return +students +shopping +account +times +sites +level +digital +profile +previous +events +hours +image +department +title +description +insurance +another +shall +property +class +still +money +quality +every +listing +content +country +private +little +visit +tools +reply +customer +december +compare +movies +include +college +value +article +provide +source +author +different +press +learn +around +print +course +canada +process +stock +training +credit +point +science +categories +advanced +sales +english +estate +conditions +select +windows +photos +thread +category +large +gallery +table +register +however +october +november +market +library +really +action +start +series +model +features +industry +human +provided +required +second +accessories +movie +forums +march +september +better +questions +yahoo +going +medical +friend +server +study +application +staff +articles +feedback +again +looking +issues +april +never +users +complete +street +topic +comment +financial +things +working +against +standard +person +below +mobile +party +payment +equipment +login +student +programs +offers +legal +above +recent +stores +problem +memory +performance +social +august +quote +language +story +options +experience +rates +create +young +america +important +field +paper +single +activities +example +girls +additional +password +latest +something +question +changes +night +texas +poker +status +browse +issue +range +building +seller +court +february +always +result +audio +light +write +offer +groups +given +files +event +release +analysis +request +china +making +picture +needs +possible +might +professional +month +major +areas +future +space +committee +cards +problems +london +washington +meeting +become +interest +child +enter +california +share +similar +garden +schools +million +added +reference +companies +listed +learning +energy +delivery +popular +stories +computers +journal +reports +welcome +central +images +president +notice +original +radio +until +color +council +includes +track +australia +discussion +archive +others +entertainment +agreement +format +least +society +months +safety +friends +trade +edition +messages +marketing +further +updated +association +having +provides +david +already +green +studies +close +common +drive +specific +several +living +collection +called +short +display +limited +powered +solutions +means +director +daily +beach +natural +whether +electronics +period +planning +database +official +weather +average +technical +window +france +region +island +record +direct +microsoft +conference +environment +records +district +calendar +costs +style +front +statement +update +parts +downloads +early +miles +sound +resource +present +applications +either +document +works +material +written +federal +hosting +rules +final +adult +tickets +thing +centre +requirements +cheap +finance +minutes +third +gifts +europe +reading +topics +individual +cover +usually +together +videos +percent +function +getting +global +economic +player +projects +lyrics +often +subscribe +submit +germany +amount +watch +included +though +thanks +everything +deals +various +words +linux +production +commercial +james +weight +heart +advertising +received +choose +treatment +newsletter +archives +points +knowledge +magazine +error +camera +currently +construction +registered +clear +receive +domain +methods +chapter +makes +protection +policies +beauty +manager +india +position +taken +listings +models +michael +known +cases +engineering +florida +simple +quick +wireless +license +friday +whole +annual +published +later +basic +shows +corporate +google +church +method +purchase +customers +active +response +practice +hardware +figure +materials +holiday +enough +designed +along +among +death +writing +speed +countries +brand +discount +higher +effects +created +remember +standards +yellow +political +increase +advertise +kingdom +environmental +thought +stuff +french +storage +japan +doing +loans +shoes +entry +nature +orders +availability +africa +summary +growth +notes +agency +monday +european +activity +although +western +income +force +employment +overall +river +commission +package +contents +players +engine +album +regional +supplies +started +administration +institute +views +plans +double +build +screen +exchange +types +sponsored +lines +electronic +continue +across +benefits +needed +season +apply +someone +anything +printer +condition +effective +believe +organization +effect +asked +sunday +selection +casino +volume +cross +anyone +mortgage +silver +corporation +inside +solution +mature +rather +weeks +addition +supply +nothing +certain +executive +running +lower +necessary +union +jewelry +according +clothing +particular +names +robert +homepage +skills +islands +advice +career +military +rental +decision +leave +british +teens +woman +facilities +sellers +middle +cable +opportunities +taking +values +division +coming +tuesday +object +lesbian +appropriate +machine +length +actually +score +statistics +client +returns +capital +follow +sample +investment +shown +saturday +christmas +england +culture +flash +george +choice +starting +registration +thursday +courses +consumer +airport +foreign +artist +outside +furniture +levels +channel +letter +phones +ideas +wednesday +structure +summer +allow +degree +contract +button +releases +homes +super +matter +custom +virginia +almost +located +multiple +asian +distribution +editor +industrial +cause +potential +focus +featured +rooms +female +responsible +communications +associated +thomas +primary +cancer +numbers +reason +browser +spring +foundation +answer +voice +friendly +schedule +documents +communication +purpose +feature +comes +police +everyone +independent +approach +cameras +brown +physical +operating +medicine +ratings +chicago +forms +glass +happy +smith +wanted +developed +thank +unique +survey +prior +telephone +sport +ready +animal +sources +mexico +population +regular +secure +navigation +operations +therefore +simply +evidence +station +christian +round +paypal +favorite +understand +option +master +valley +recently +probably +rentals +built +publications +blood +worldwide +improve +connection +publisher +larger +networks +earth +parents +nokia +impact +transfer +introduction +kitchen +strong +carolina +wedding +properties +hospital +ground +overview +accommodation +owners +disease +excellent +italy +perfect +opportunity +classic +basis +command +cities +william +express +award +distance +peter +assessment +ensure +involved +extra +especially +interface +partners +budget +rated +guides +success +maximum +operation +existing +quite +selected +amazon +patients +restaurants +beautiful +warning +locations +horse +forward +flowers +stars +significant +lists +technologies +owner +retail +animals +useful +directly +manufacturer +providing +housing +takes +bring +catalog +searches +trying +mother +authority +considered +traffic +programme +joined +input +strategy +agent +valid +modern +senior +ireland +teaching +grand +testing +trial +charge +units +instead +canadian +normal +wrote +enterprise +ships +entire +educational +leading +metal +positive +fitness +chinese +opinion +football +abstract +output +funds +greater +likely +develop +employees +artists +alternative +processing +responsibility +resolution +guest +seems +publication +relations +trust +contains +session +multi +photography +republic +components +vacation +century +academic +assistance +completed +graphics +indian +expected +grade +dating +pacific +mountain +organizations +filter +mailing +vehicle +longer +consider +northern +behind +panel +floor +german +buying +match +proposed +default +require +outdoor +morning +otherwise +allows +protein +plant +reported +transportation +politics +partner +disclaimer +authors +boards +faculty +parties +membership +mission +string +sense +modified +released +stage +internal +goods +recommended +unless +richard +detailed +japanese +approved +background +target +except +character +maintenance +ability +maybe +functions +moving +brands +places +pretty +trademarks +phentermine +spain +southern +yourself +winter +battery +youth +pressure +submitted +boston +keywords +medium +television +interested +break +purposes +throughout +dance +itself +defined +papers +playing +awards +studio +reader +virtual +device +established +answers +remote +programming +external +apple +regarding +instructions +offered +theory +enjoy +remove +surface +minimum +visual +variety +teachers +martin +manual +block +subjects +agents +increased +repair +civil +steel +understanding +songs +fixed +wrong +beginning +hands +associates +finally +updates +desktop +classes +paris +sector +capacity +requires +jersey +fully +father +electric +instruments +quotes +officer +driver +businesses +respect +unknown +specified +restaurant +worth +procedures +teacher +relationship +workers +georgia +peace +traditional +campus +showing +creative +coast +benefit +progress +funding +devices +grant +agree +fiction +sometimes +watches +careers +beyond +families +museum +themselves +transport +interesting +blogs +evaluation +accepted +former +implementation +complex +galleries +references +presented +agencies +literature +respective +parent +spanish +michigan +columbia +setting +scale +stand +economy +highest +helpful +monthly +critical +frame +musical +definition +secretary +angeles +networking +australian +employee +chief +gives +bottom +magazines +packages +detail +francisco +changed +heard +begin +individuals +colorado +royal +clean +switch +russian +largest +african +titles +relevant +guidelines +justice +connect +bible +basket +applied +weekly +installation +described +demand +suite +vegas +square +chris +attention +advance +auction +difference +allowed +correct +charles +nation +selling +piece +sheet +seven +older +illinois +regulations +elements +species +cells +module +resort +facility +random +pricing +certificate +minister +motion +looks +fashion +directions +visitors +documentation +monitor +trading +forest +calls +whose +coverage +couple +giving +chance +vision +ending +clients +actions +listen +discuss +accept +automotive +naked +successful +communities +clinical +situation +sciences +markets +lowest +highly +publishing +appear +emergency +developing +lives +currency +leather +determine +temperature +announcements +patient +actual +historical +stone +commerce +ringtones +perhaps +persons +difficult +scientific +satellite +tests +village +accounts +amateur +particularly +factors +coffee +settings +buyer +cultural +steve +easily +poster +functional +closed +holidays +zealand +balance +monitoring +graduate +replies +architecture +initial +label +thinking +scott +recommend +canon +league +waste +minute +provider +optional +dictionary +accounting +manufacturing +sections +chair +fishing +effort +phase +fields +fantasy +letters +motor +professor +context +install +shirt +apparel +generally +continued +crime +count +breast +techniques +johnson +quickly +dollars +websites +religion +claim +driving +permission +surgery +patch +measures +generation +kansas +chemical +doctor +reduce +brought +himself +component +enable +exercise +santa +guarantee +leader +diamond +israel +processes +servers +alone +meetings +seconds +jones +arizona +keyword +interests +flight +congress +username +produced +italian +paperback +classifieds +supported +pocket +saint +freedom +argument +competition +creating +drugs +joint +premium +providers +fresh +characters +attorney +upgrade +factor +growing +thousands +stream +apartments +hearing +eastern +auctions +therapy +entries +dates +generated +signed +upper +administrative +serious +prime +samsung +limit +began +louis +steps +errors +shops +efforts +informed +thoughts +creek +worked +quantity +urban +practices +sorted +reporting +essential +myself +tours +platform +affiliate +labor +immediately +admin +nursing +defense +machines +designated +heavy +covered +recovery +integrated +configuration +merchant +comprehensive +expert +universal +protect +solid +presentation +languages +became +orange +compliance +vehicles +prevent +theme +campaign +marine +improvement +guitar +finding +pennsylvania +examples +saying +spirit +claims +challenge +motorola +acceptance +strategies +affairs +touch +intended +towards +goals +election +suggest +branch +charges +serve +affiliates +reasons +magic +mount +smart +talking +latin +multimedia +avoid +certified +manage +corner +computing +oregon +element +birth +virus +abuse +interactive +requests +separate +quarter +procedure +leadership +tables +define +racing +religious +facts +breakfast +column +plants +faith +chain +developer +identify +avenue +missing +approximately +domestic +sitemap +recommendations +moved +houston +reach +comparison +mental +viewed +moment +extended +sequence +attack +sorry +centers +opening +damage +reserve +recipes +gamma +plastic +produce +placed +truth +counter +failure +follows +weekend +dollar +ontario +automatically +minnesota +films +bridge +native +williams +movement +printing +baseball +owned +approval +draft +chart +played +contacts +jesus +readers +clubs +jackson +equal +adventure +matching +offering +shirts +profit +leaders +posters +institutions +assistant +variable +advertisement +expect +parking +headlines +yesterday +compared +determined +wholesale +workshop +russia +codes +kinds +extension +seattle +statements +golden +completely +teams +lighting +senate +forces +funny +brother +turned +portable +tried +electrical +applicable +returned +pattern +named +theatre +laser +earlier +manufacturers +sponsor +classical +warranty +dedicated +indiana +direction +harry +basketball +objects +delete +evening +assembly +nuclear +taxes +mouse +signal +criminal +issued +brain +sexual +wisconsin +powerful +dream +obtained +false +flower +personnel +passed +supplied +identified +falls +opinions +promote +stated +stats +hawaii +professionals +appears +carry +decided +covers +advantage +hello +designs +maintain +tourism +priority +newsletters +adults +clips +savings +graphic +payments +estimated +binding +brief +ended +winning +eight +anonymous +straight +script +served +wants +miscellaneous +prepared +dining +alert +integration +atlanta +dakota +interview +framework +installed +queen +credits +clearly +handle +sweet +criteria +pubmed +massachusetts +diego +associate +truck +behavior +enlarge +frequently +revenue +measure +changing +votes +looked +discussions +festival +laboratory +ocean +flights +experts +signs +depth +whatever +logged +laptop +vintage +train +exactly +explore +maryland +concept +nearly +eligible +checkout +reality +forgot +handling +origin +gaming +feeds +billion +destination +scotland +faster +intelligence +dallas +bought +nations +route +followed +specifications +broken +tripadvisor +frank +alaska +battle +residential +anime +speak +decisions +industries +protocol +query +partnership +editorial +expression +equity +provisions +speech +principles +suggestions +rural +shared +sounds +replacement +strategic +judge +economics +bytes +forced +compatible +fight +apartment +height +speaker +filed +netherlands +obtain +consulting +recreation +offices +designer +remain +managed +failed +marriage +korea +banks +participants +secret +kelly +leads +negative +austin +favorites +toronto +theater +springs +missouri +andrew +perform +healthy +translation +estimates +assets +injury +joseph +ministry +drivers +lawyer +figures +married +protected +proposal +sharing +philadelphia +portal +waiting +birthday +gratis +banking +officials +brian +toward +slightly +assist +conduct +contained +lingerie +legislation +calling +parameters +serving +profiles +miami +comics +matters +houses +postal +relationships +tennessee +controls +breaking +combined +ultimate +wales +representative +frequency +introduced +minor +finish +departments +residents +noted +displayed +reduced +physics +spent +performed +extreme +samples +davis +daniel +reviewed +forecast +removed +helps +singles +administrator +cycle +amounts +contain +accuracy +sleep +pharmacy +brazil +creation +static +scene +hunter +addresses +crystal +famous +writer +chairman +violence +oklahoma +speakers +drink +academy +dynamic +gender +permanent +agriculture +cleaning +constitutes +portfolio +practical +delivered +collectibles +infrastructure +exclusive +concerns +colour +vendor +originally +intel +utilities +philosophy +regulation +officers +reduction +referred +supports +nutrition +recording +regions +junior +rings +meaning +secondary +wonderful +ladies +henry +ticket +announced +guess +agreed +prevention +soccer +import +posting +presence +instant +mentioned +automatic +healthcare +viewing +maintained +increasing +majority +connected +christ +directors +aspects +austria +ahead +participation +scheme +utility +preview +manner +matrix +containing +combination +devel +amendment +despite +strength +guaranteed +turkey +libraries +proper +distributed +degrees +singapore +enterprises +delta +seeking +inches +phoenix +convention +shares +principal +daughter +standing +comfort +colors +cisco +ordering +alpha +appeal +cruise +bonus +certification +previously +bookmark +buildings +specials +disney +household +batteries +adobe +smoking +becomes +drives +alabama +improved +trees +achieve +positions +dress +subscription +dealer +contemporary +nearby +carried +happen +exposure +panasonic +permalink +signature +gambling +refer +miller +provision +outdoors +clothes +caused +luxury +babes +frames +certainly +indeed +newspaper +circuit +layer +printed +removal +easier +liability +trademark +printers +adding +kentucky +mostly +taylor +trackback +prints +spend +factory +interior +revised +americans +optical +promotion +relative +amazing +clock +identity +suites +conversion +feeling +hidden +reasonable +victoria +serial +relief +revision +broadband +influence +ratio +importance +planet +webmaster +copies +recipe +permit +seeing +proof +tennis +prescription +bedroom +empty +instance +licensed +orlando +specifically +bureau +maine +represent +conservation +ideal +specs +recorded +pieces +finished +parks +dinner +lawyers +sydney +stress +cream +trends +discover +patterns +boxes +louisiana +hills +javascript +fourth +advisor +marketplace +aware +wilson +shape +evolution +irish +certificates +objectives +stations +suggested +remains +greatest +firms +concerned +operator +structures +generic +encyclopedia +usage +charts +continuing +mixed +census +interracial +competitive +exist +wheel +transit +suppliers +compact +poetry +lights +tracking +angel +keeping +preparation +attempt +receiving +matches +accordance +width +noise +engines +forget +array +discussed +accurate +stephen +elizabeth +climate +reservations +playstation +alcohol +greek +instruction +managing +annotation +sister +differences +walking +explain +smaller +newest +establish +happened +expressed +extent +sharp +lesbians +paragraph +mathematics +compensation +export +managers +aircraft +modules +sweden +conflict +conducted +versions +employer +occur +percentage +knows +mississippi +describe +concern +backup +requested +citizens +connecticut +heritage +personals +immediate +holding +trouble +spread +coach +kevin +agricultural +expand +supporting +audience +assigned +jordan +collections +participate +specialist +affect +virgin +experienced +investigation +raised +institution +directed +dealers +searching +sporting +helping +affected +totally +plate +expenses +indicate +blonde +proceedings +favourite +transmission +anderson +characteristics +organic +experiences +albums +cheats +extremely +verzeichnis +contracts +guests +hosted +diseases +concerning +developers +equivalent +chemistry +neighborhood +nevada +thailand +variables +agenda +anyway +continues +tracks +advisory +curriculum +logic +template +prince +circle +grants +anywhere +psychology +responses +atlantic +circumstances +edward +investor +identification +leaving +wildlife +appliances +elementary +cooking +speaking +sponsors +unlimited +respond +sizes +plain +entered +launch +checking +costa +belgium +printable +guidance +trail +enforcement +symbol +crafts +highway +buddy +hardcover +observed +setup +booking +glossary +fiscal +celebrity +styles +denver +filled +channels +ericsson +appendix +notify +blues +chocolate +portion +scope +hampshire +supplier +cables +cotton +bluetooth +controlled +requirement +authorities +biology +dental +killed +border +ancient +debate +representatives +starts +pregnancy +causes +arkansas +biography +leisure +attractions +learned +transactions +notebook +explorer +historic +attached +opened +husband +disabled +authorized +crazy +upcoming +britain +concert +retirement +scores +financing +efficiency +comedy +adopted +efficient +weblog +linear +commitment +specialty +bears +carrier +edited +constant +mouth +jewish +meter +linked +portland +interviews +concepts +reflect +deliver +wonder +lessons +fruit +begins +qualified +reform +alerts +treated +discovery +mysql +classified +relating +assume +confidence +alliance +confirm +neither +lewis +howard +offline +leaves +engineer +lifestyle +consistent +replace +clearance +connections +inventory +converter +organisation +checks +reached +becoming +safari +objective +indicated +sugar +stick +securities +allen +relation +enabled +genre +slide +montana +volunteer +tested +democratic +enhance +switzerland +exact +bound +parameter +adapter +processor +formal +dimensions +contribute +hockey +storm +micro +colleges +laptops +showed +challenges +editors +threads +supreme +brothers +recognition +presents +submission +dolls +estimate +encourage +regulatory +inspection +consumers +cancel +limits +territory +transaction +manchester +weapons +paint +delay +pilot +outlet +contributions +continuous +czech +resulting +cambridge +initiative +novel +execution +disability +increases +ultra +winner +idaho +contractor +episode +examination +potter +plays +bulletin +indicates +modify +oxford +truly +epinions +painting +committed +extensive +affordable +universe +candidate +databases +patent +outstanding +eating +perspective +planned +watching +lodge +messenger +mirror +tournament +consideration +discounts +sterling +sessions +kernel +stocks +buyers +journals +catalogue +jennifer +antonio +charged +broad +taiwan +chosen +greece +swiss +sarah +clark +labour +terminal +publishers +nights +behalf +caribbean +liquid +nebraska +salary +reservation +foods +gourmet +guard +properly +orleans +saving +remaining +empire +resume +twenty +newly +raise +prepare +avatar +depending +illegal +expansion +hundreds +lincoln +helped +premier +tomorrow +purchased +decide +consent +drama +visiting +performing +downtown +keyboard +contest +collected +bands +suitable +absolutely +millions +lunch +audit +chamber +guinea +findings +muscle +featuring +implement +clicking +scheduled +polls +typical +tower +yours +calculator +significantly +chicken +temporary +attend +shower +sending +jason +tonight +sufficient +holdem +shell +province +catholic +awareness +vancouver +governor +seemed +contribution +measurement +swimming +spyware +formula +constitution +packaging +solar +catch +pakistan +reliable +consultation +northwest +doubt +finder +unable +periods +classroom +tasks +democracy +attacks +wallpaper +merchandise +const +resistance +doors +symptoms +resorts +biggest +memorial +visitor +forth +insert +baltimore +gateway +alumni +drawing +candidates +charlotte +ordered +biological +fighting +transition +happens +preferences +romance +instrument +bruce +split +themes +powers +heaven +pregnant +twice +classification +focused +egypt +physician +hollywood +bargain +wikipedia +cellular +norway +vermont +asking +blocks +normally +spiritual +hunting +diabetes +shift +bodies +photographs +cutting +simon +writers +marks +flexible +loved +favourites +mapping +numerous +relatively +birds +satisfaction +represents +indexed +pittsburgh +superior +preferred +saved +paying +cartoon +shots +intellectual +moore +granted +choices +carbon +spending +comfortable +magnetic +interaction +listening +effectively +registry +crisis +outlook +massive +denmark +employed +bright +treat +header +poverty +formed +piano +sheets +patrick +experimental +puerto +revolution +consolidation +displays +plasma +allowing +earnings +mystery +landscape +dependent +mechanical +journey +delaware +bidding +consultants +risks +banner +applicant +charter +barbara +cooperation +counties +acquisition +ports +implemented +directories +recognized +dreams +blogger +notification +licensing +stands +teach +occurred +textbooks +rapid +hairy +diversity +cleveland +reverse +deposit +seminar +investments +latina +wheels +specify +accessibility +dutch +sensitive +templates +formats +depends +boots +holds +router +concrete +editing +poland +folder +womens +completion +upload +pulse +universities +technique +contractors +voting +courts +notices +subscriptions +calculate +detroit +alexander +broadcast +converted +metro +toshiba +anniversary +improvements +strip +specification +pearl +accident +accessible +accessory +resident +possibly +airline +typically +representation +regard +exists +arrangements +smooth +conferences +uniprotkb +strike +consumption +birmingham +flashing +narrow +afternoon +threat +surveys +sitting +putting +consultant +controller +ownership +committees +legislative +researchers +vietnam +trailer +castle +gardens +missed +malaysia +unsubscribe +antique +labels +willing +molecular +acting +heads +stored +logos +residence +attorneys +antiques +density +hundred +operators +strange +sustainable +philippines +statistical +mention +innovation +employers +parallel +honda +amended +operate +bills +bathroom +stable +opera +definitions +doctors +lesson +cinema +asset +elections +drinking +reaction +blank +enhanced +entitled +severe +generate +stainless +newspapers +hospitals +deluxe +humor +monitors +exception +lived +duration +successfully +indonesia +pursuant +fabric +visits +primarily +tight +domains +capabilities +contrast +recommendation +flying +recruitment +berlin +organized +siemens +adoption +improving +expensive +meant +capture +pounds +buffalo +organisations +plane +explained +programmes +desire +expertise +mechanism +camping +jewellery +meets +welfare +caught +eventually +marked +driven +measured +medline +bottle +agreements +considering +innovative +marshall +massage +rubber +conclusion +closing +tampa +thousand +legend +grace +susan +adams +python +monster +villa +columns +disorders +collaboration +hamilton +detection +cookies +inner +formation +tutorial +engineers +entity +cruises +holder +proposals +moderator +tutorials +settlement +portugal +lawrence +roman +duties +valuable +collectables +ethics +forever +dragon +captain +fantastic +imagine +brings +heating +governments +purchasing +scripts +stereo +appointed +taste +dealing +commit +operational +airlines +liberal +livecam +trips +sides +turns +corresponding +descriptions +cache +jacket +determination +animation +oracle +matthew +lease +productions +aviation +hobbies +proud +excess +disaster +console +commands +telecommunications +instructor +giant +achieved +injuries +shipped +seats +approaches +alarm +voltage +anthony +nintendo +usual +loading +stamps +appeared +franklin +angle +vinyl +highlights +mining +designers +melbourne +ongoing +worst +imaging +betting +scientists +liberty +wyoming +blackjack +argentina +convert +possibility +analyst +commissioner +dangerous +garage +exciting +reliability +thongs +unfortunately +respectively +volunteers +attachment +ringtone +finland +morgan +derived +pleasure +honor +oriented +eagle +desktops +pants +columbus +nurse +prayer +appointment +workshops +hurricane +quiet +postage +producer +represented +mortgages +responsibilities +cheese +comic +carefully +productivity +investors +crown +underground +diagnosis +maker +crack +principle +picks +vacations +semester +calculated +fetish +applies +casinos +appearance +smoke +apache +filters +incorporated +craft +notebooks +apart +fellow +blind +lounge +algorithm +coins +gross +strongly +valentine +hilton +proteins +horror +familiar +capable +douglas +debian +involving +investing +christopher +admission +epson +elected +carrying +victory +madison +terrorism +editions +mainly +ethnic +parliament +actor +finds +situations +fifth +allocated +citizen +vertical +corrections +structural +municipal +describes +prize +occurs +absolute +disabilities +consists +anytime +substance +prohibited +addressed +soldiers +guardian +lecture +simulation +layout +initiatives +concentration +classics +interpretation +horses +dirty +wayne +donate +taught +bankruptcy +worker +optimization +alive +temple +substances +prove +discovered +wings +breaks +genetic +restrictions +participating +waters +promise +exhibition +prefer +ridge +cabinet +modem +harris +bringing +evaluate +tiffany +tropical +collect +composition +toyota +streets +nationwide +vector +definitely +shaved +turning +buffer +purple +existence +commentary +larry +limousines +developments +immigration +destinations +mutual +pipeline +necessarily +syntax +attribute +prison +skill +chairs +everyday +apparently +surrounding +mountains +moves +popularity +inquiry +ethernet +checked +exhibit +throw +trend +sierra +visible +desert +postposted +oldest +rhode +coordinator +obviously +mercury +steven +handbook +navigate +worse +summit +victims +spaces +fundamental +burning +escape +coupons +somewhat +receiver +substantial +progressive +cialis +boats +glance +scottish +championship +arcade +richmond +sacramento +impossible +russell +tells +obvious +fiber +depression +graph +covering +platinum +judgment +bedrooms +talks +filing +foster +modeling +passing +awarded +testimonials +trials +tissue +memorabilia +clinton +masters +bonds +cartridge +alberta +explanation +commons +cincinnati +subsection +fraud +electricity +permitted +spectrum +arrival +pottery +emphasis +roger +aspect +workplace +awesome +mexican +confirmed +counts +priced +wallpapers +crash +desired +inter +closer +assumes +heights +shadow +riding +infection +firefox +expense +grove +eligibility +venture +clinic +korean +healing +princess +entering +packet +spray +studios +involvement +buttons +placement +observations +vbulletin +funded +thompson +winners +extend +roads +subsequent +dublin +rolling +motorcycle +disclosure +establishment +memories +nelson +arrived +creates +faces +tourist +mayor +murder +adequate +senator +yield +presentations +grades +cartoons +digest +lodging +hence +entirely +replaced +radar +rescue +undergraduate +losses +combat +reducing +stopped +occupation +lakes +donations +associations +citysearch +closely +radiation +diary +seriously +kings +shooting +flags +baker +launched +elsewhere +pollution +conservative +guestbook +shock +effectiveness +walls +abroad +ebony +drawn +arthur +visited +walker +demonstrate +atmosphere +suggests +beast +operated +experiment +targets +overseas +purchases +dodge +counsel +federation +pizza +invited +yards +assignment +chemicals +gordon +farmers +queries +ukraine +absence +nearest +cluster +vendors +whereas +serves +woods +surprise +partial +shoppers +everybody +couples +nashville +ranking +jokes +simpson +twiki +sublime +counseling +palace +acceptable +satisfied +measurements +verify +globe +trusted +copper +milwaukee +medication +warehouse +shareware +dicke +kerry +receipt +supposed +ordinary +nobody +ghost +violation +configure +stability +applying +southwest +pride +institutional +expectations +independence +knowing +reporter +metabolism +keith +champion +cloudy +linda +personally +chile +plenty +sentence +throat +ignore +maria +uniform +excellence +wealth +somewhere +vacuum +dancing +attributes +recognize +brass +writes +plaza +outcomes +survival +quest +publish +screening +thumbnail +trans +jonathan +whenever +lifetime +pioneer +booty +forgotten +acrobat +plates +acres +venue +athletic +thermal +essays +behaviour +vital +telling +fairly +coastal +config +charity +intelligent +edinburgh +excel +modes +obligation +campbell +stupid +harbor +hungary +traveler +segment +realize +regardless +enemy +puzzle +rising +aluminum +wells +wishlist +opens +insight +restricted +republican +secrets +lucky +latter +merchants +thick +trailers +repeat +syndrome +philips +attendance +penalty +glasses +enables +iraqi +builder +vista +jessica +chips +terry +flood +arguments +amsterdam +arena +adventures +pupils +stewart +announcement +outcome +appreciate +expanded +casual +grown +polish +lovely +extras +centres +jerry +clause +smile +lands +troops +indoor +bulgaria +armed +broker +charger +regularly +believed +cooling +trucks +mechanisms +divorce +laura +shopper +tokyo +partly +nikon +customize +tradition +candy +pills +tiger +donald +folks +sensor +exposed +telecom +angels +deputy +indicators +sealed +emissions +physicians +loaded +complaint +scenes +experiments +afghanistan +boost +spanking +scholarship +governance +founded +supplements +chronic +icons +moral +catering +finger +keeps +pound +locate +camcorder +trained +implementing +roses +ourselves +bread +tobacco +wooden +motors +tough +roberts +incident +gonna +dynamics +conversation +decrease +chest +pension +billy +revenues +emerging +worship +capability +craig +herself +producing +churches +precision +damages +reserves +contributed +solve +shorts +reproduction +minority +diverse +ingredients +johnny +franchise +recorder +complaints +facing +nancy +promotions +tones +passion +rehabilitation +maintaining +sight +defence +patches +refund +towns +environments +trembl +divided +reception +emails +cyprus +correctly +insider +seminars +consequences +makers +hearts +geography +appearing +integrity +worry +discrimination +carter +legacy +pleased +danger +vitamin +widely +processed +phrase +genuine +raising +implications +functionality +paradise +hybrid +reads +roles +intermediate +emotional +glory +platforms +bigger +billing +diesel +versus +combine +overnight +geographic +exceed +saudi +fault +preliminary +districts +introduce +promotional +chevrolet +babies +karen +compiled +romantic +revealed +specialists +generator +albert +examine +jimmy +graham +suspension +bristol +margaret +compaq +correction +slowly +authentication +communicate +rugby +supplement +showtimes +portions +infant +promoting +sectors +samuel +fluid +grounds +regards +machinery +bandwidth +unlike +equation +baskets +probability +dimension +wright +barry +proven +schedules +admissions +cached +warren +studied +reviewer +involves +quarterly +profits +devil +grass +comply +marie +florist +illustrated +cherry +continental +alternate +deutsch +achievement +limitations +kenya +webcam +funeral +nutten +earrings +enjoyed +automated +chapters +charlie +quebec +passenger +convenient +dennis +francis +sized +manga +noticed +socket +silent +literary +signals +orientation +theft +childhood +swing +symbols +humans +analog +facial +choosing +talent +dated +flexibility +seeker +wisdom +shoot +boundary +packard +offset +payday +philip +elite +holders +believes +swedish +poems +deadline +jurisdiction +robot +displaying +witness +collins +equipped +stages +encouraged +winds +powder +broadway +acquired +assess +cartridges +stones +entrance +gnome +roots +declaration +losing +attempts +gadgets +noble +glasgow +automation +impacts +gospel +advantages +shore +loves +induced +knight +preparing +loose +recipient +linking +extensions +appeals +earned +illness +islamic +athletics +southeast +alternatives +pending +parker +determining +lebanon +personalized +kennedy +conditioning +teenage +triple +cooper +vincent +secured +unusual +answered +partnerships +destruction +slots +increasingly +migration +disorder +routine +toolbar +basically +rocks +conventional +titans +applicants +wearing +sought +genes +mounted +habitat +firewall +median +scanner +herein +occupational +animated +judicial +adjustment +integer +treatments +bachelor +attitude +camcorders +engaged +falling +basics +montreal +carpet +struct +lenses +binary +genetics +attended +difficulty +collective +coalition +dropped +enrollment +walter +besides +producers +collector +hosts +interfaces +advertisers +moments +atlas +strings +representing +observation +feels +torture +deleted +mitchell +restoration +convenience +returning +ralph +opposition +container +defendant +warner +confirmation +embedded +inkjet +supervisor +wizard +corps +actors +liver +peripherals +liable +brochure +morris +bestsellers +petition +eminem +recall +antenna +picked +assumed +departure +minneapolis +belief +killing +bikini +memphis +shoulder +decor +lookup +texts +harvard +brokers +diameter +ottawa +podcast +seasons +interactions +refine +bidder +singer +evans +herald +literacy +fails +aging +intervention +plugin +attraction +diving +invite +modification +alice +latinas +suppose +customized +involve +moderate +terror +younger +thirty +opposite +understood +rapidly +dealtime +intro +mercedes +assurance +clerk +happening +mills +outline +amendments +tramadol +holland +receives +jeans +metropolitan +compilation +verification +fonts +refers +favor +veterans +sigma +attractive +xhtml +occasion +recordings +jefferson +victim +demands +sleeping +careful +gardening +obligations +arrive +orchestra +sunset +tracked +moreover +minimal +polyphonic +lottery +framed +aside +outsourcing +licence +adjustable +allocation +michelle +essay +discipline +demonstrated +dialogue +identifying +alphabetical +camps +declared +dispatched +aaron +handheld +trace +disposal +florists +packs +installing +switches +romania +voluntary +consult +greatly +blogging +cycling +midnight +commonly +photographer +inform +turkish +messaging +pentium +quantum +murray +intent +largely +pleasant +announce +constructed +additions +requiring +spoke +arrow +engagement +sampling +rough +weird +refinance +inspired +holes +weddings +blade +suddenly +oxygen +cookie +meals +canyon +meters +merely +calendars +arrangement +conclusions +passes +bibliography +pointer +compatibility +stretch +durham +furthermore +permits +cooperative +muslim +sleeve +netscape +cleaner +cricket +feeding +stroke +township +rankings +measuring +robin +robinson +jacksonville +strap +headquarters +sharon +crowd +transfers +olympic +transformation +remained +attachments +entities +customs +administrators +personality +rainbow +roulette +decline +gloves +israeli +medicare +skiing +cloud +facilitate +subscriber +valve +hewlett +explains +proceed +flickr +feelings +knife +jamaica +priorities +shelf +bookstore +timing +liked +parenting +adopt +denied +fotos +incredible +britney +freeware +donation +outer +deaths +rivers +commonwealth +pharmaceutical +manhattan +tales +katrina +workforce +islam +nodes +thumbs +seeds +cited +targeted +organizational +skype +realized +twelve +founder +decade +gamecube +dispute +portuguese +tired +titten +adverse +everywhere +excerpt +steam +discharge +drinks +voices +acute +halloween +climbing +stood +perfume +carol +honest +albany +hazardous +restore +stack +methodology +somebody +housewares +reputation +resistant +democrats +recycling +curve +creator +amber +qualifications +museums +coding +slideshow +tracker +variation +passage +transferred +trunk +hiking +pierre +jelsoft +headset +photograph +oakland +colombia +waves +camel +distributor +lamps +underlying +wrestling +suicide +archived +photoshop +arabia +gathering +projection +juice +chase +mathematical +logical +sauce +extract +specialized +diagnostic +panama +indianapolis +payable +corporations +courtesy +criticism +automobile +confidential +statutory +accommodations +athens +northeast +downloaded +judges +retired +remarks +detected +decades +paintings +walked +arising +nissan +bracelet +juvenile +injection +yorkshire +populations +protective +afraid +acoustic +railway +cassette +initially +indicator +pointed +causing +mistake +norton +locked +eliminate +fusion +mineral +sunglasses +steering +beads +fortune +preference +canvas +threshold +parish +claimed +screens +cemetery +planner +croatia +flows +stadium +venezuela +exploration +fewer +sequences +coupon +nurses +proxy +astronomy +lanka +edwards +contests +translate +announces +costume +tagged +berkeley +voted +killer +bikes +gates +adjusted +bishop +pulled +shaped +compression +seasonal +establishing +farmer +counters +constitutional +perfectly +slave +instantly +cultures +norfolk +coaching +examined +encoding +litigation +submissions +heroes +painted +lycos +zdnet +broadcasting +horizontal +artwork +cosmetic +resulted +portrait +terrorist +informational +ethical +carriers +ecommerce +mobility +floral +builders +struggle +schemes +suffering +neutral +fisher +spears +prospective +bedding +ultimately +joining +heading +equally +artificial +bearing +spectacular +coordination +connector +combo +seniors +worlds +guilty +affiliated +activation +naturally +haven +tablet +subscribers +charm +violent +mitsubishi +underwear +basin +potentially +ranch +constraints +crossing +inclusive +dimensional +cottage +drunk +considerable +crimes +resolved +mozilla +toner +latex +branches +anymore +delhi +holdings +alien +locator +selecting +processors +pantyhose +broke +nepal +zimbabwe +difficulties +complexity +constantly +browsing +resolve +barcelona +presidential +documentary +territories +melissa +moscow +thesis +nylon +palestinian +discs +rocky +bargains +frequent +nigeria +ceiling +pixels +ensuring +hispanic +legislature +hospitality +anybody +procurement +diamonds +fleet +untitled +bunch +totals +marriott +singing +theoretical +afford +exercises +starring +referral +surveillance +optimal +distinct +protocols +highlight +substitute +inclusion +hopefully +brilliant +turner +sucking +cents +reuters +spoken +omega +evaluated +stayed +civic +assignments +manuals +termination +watched +saver +thereof +grill +households +redeem +rogers +grain +authentic +regime +wanna +wishes +montgomery +architectural +louisville +depend +differ +macintosh +movements +ranging +monica +repairs +breath +amenities +virtually +candle +hanging +colored +authorization +verified +formerly +projector +situated +comparative +seeks +herbal +loving +strictly +routing +stanley +psychological +surprised +retailer +vitamins +elegant +gains +renewal +genealogy +opposed +deemed +scoring +expenditure +brooklyn +liverpool +sisters +critics +connectivity +spots +algorithms +hacker +madrid +similarly +margin +solely +salon +collaborative +norman +excluding +turbo +headed +voters +madonna +commander +murphy +thinks +thats +suggestion +soldier +phillips +aimed +justin +interval +mirrors +spotlight +tricks +reset +brush +investigate +expansys +panels +repeated +assault +connecting +spare +logistics +kodak +tongue +bowling +danish +monkey +proportion +filename +skirt +florence +invest +honey +analyses +drawings +significance +scenario +lovers +atomic +approx +symposium +arabic +gauge +essentials +junction +protecting +faced +rachel +solving +transmitted +weekends +screenshots +produces +intensive +chains +kingston +sixth +engage +deviant +switching +quoted +adapters +correspondence +farms +imports +supervision +cheat +bronze +expenditures +sandy +separation +testimony +suspect +celebrities +macro +sender +mandatory +boundaries +crucial +syndication +celebration +adjacent +filtering +tuition +spouse +exotic +viewer +signup +threats +luxembourg +puzzles +reaching +damaged +receptor +laugh +surgical +destroy +citation +pitch +autos +premises +perry +proved +offensive +imperial +dozen +benjamin +deployment +teeth +cloth +studying +colleagues +stamp +lotus +salmon +olympus +separated +cargo +directive +salem +starter +upgrades +likes +butter +pepper +weapon +luggage +burden +tapes +zones +races +stylish +maple +grocery +offshore +governing +retailers +depot +kenneth +blend +harrison +julie +occasionally +attending +emission +finest +realty +janet +recruiting +apparent +instructional +phpbb +autumn +traveling +probe +permissions +biotechnology +toilet +ranked +jackets +routes +packed +excited +outreach +helen +mounting +recover +lopez +balanced +prescribed +catherine +timely +talked +debug +delayed +chuck +reproduced +explicit +calculation +villas +ebook +consolidated +exclude +peeing +occasions +brooks +equations +newton +exceptional +anxiety +bingo +whilst +spatial +respondents +ceramic +prompt +precious +minds +annually +considerations +scanners +xanax +fingers +sunny +ebooks +delivers +queensland +necklace +musicians +leeds +composite +unavailable +cedar +arranged +theaters +advocacy +raleigh +essentially +designing +threaded +qualify +blair +hopes +assessments +mason +diagram +burns +pumps +footwear +beijing +peoples +victor +mario +attach +licenses +utils +removing +advised +brunswick +spider +ranges +pairs +sensitivity +trails +preservation +hudson +isolated +calgary +interim +assisted +divine +streaming +approve +chose +compound +intensity +technological +syndicate +abortion +dialog +venues +blast +wellness +calcium +newport +antivirus +addressing +discounted +indians +shield +harvest +membrane +prague +previews +bangladesh +constitute +locally +concluded +pickup +desperate +mothers +nascar +iceland +demonstration +governmental +manufactured +candles +graduation +sailing +variations +sacred +addiction +morocco +chrome +tommy +springfield +refused +brake +exterior +greeting +ecology +oliver +congo +botswana +delays +synthesis +olive +undefined +unemployment +cyber +verizon +scored +enhancement +newcastle +clone +dicks +velocity +lambda +relay +composed +tears +performances +oasis +baseline +angry +societies +silicon +brazilian +identical +petroleum +compete +norwegian +lover +belong +honolulu +beatles +retention +exchanges +rolls +thomson +barnes +soundtrack +wondering +malta +daddy +ferry +rabbit +profession +seating +separately +physiology +collecting +exports +omaha +participant +scholarships +recreational +dominican +electron +loads +friendship +heather +passport +motel +unions +treasury +warrant +solaris +frozen +occupied +royalty +scales +rally +observer +sunshine +strain +ceremony +somehow +arrested +expanding +provincial +investigations +yamaha +medications +hebrew +gained +rochester +dying +laundry +stuck +solomon +placing +stops +homework +adjust +assessed +advertiser +enabling +encryption +filling +downloadable +sophisticated +imposed +silence +focuses +soviet +possession +laboratories +treaty +vocal +trainer +organ +stronger +volumes +advances +vegetables +lemon +toxic +thumbnails +darkness +bizrate +vienna +implied +stanford +stockings +respondent +packing +statute +rejected +satisfy +destroyed +shelter +chapel +gamespot +manufacture +layers +wordpress +guided +vulnerability +accountability +celebrate +accredited +appliance +compressed +bahamas +powell +mixture +bench +rider +scheduling +radius +perspectives +mortality +logging +hampton +christians +borders +therapeutic +butts +bobby +impressive +sheep +accordingly +architect +railroad +lectures +challenging +wines +nursery +harder +microwave +cheapest +accidents +travesti +relocation +stuart +contributors +salvador +salad +monroe +tender +violations +temperatures +paste +clouds +competitions +discretion +tanzania +preserve +unsigned +staying +cosmetics +easter +theories +repository +praise +jeremy +venice +concentrations +estonia +christianity +veteran +streams +landing +signing +executed +katie +negotiations +realistic +showcase +integral +relax +namibia +generating +christina +congressional +synopsis +hardly +prairie +reunion +composer +sword +absent +photographic +sells +ecuador +hoping +accessed +spirits +modifications +coral +pixel +float +colin +imported +paths +bubble +acquire +contrary +millennium +tribune +vessel +acids +focusing +viruses +cheaper +admitted +dairy +admit +fancy +equality +samoa +achieving +stickers +fisheries +exceptions +reactions +leasing +lauren +beliefs +macromedia +companion +squad +analyze +ashley +scroll +relate +divisions +wages +additionally +suffer +forests +fellowship +invalid +concerts +martial +males +victorian +retain +colours +execute +tunnel +genres +cambodia +patents +copyrights +chaos +lithuania +mastercard +wheat +chronicles +obtaining +beaver +updating +distribute +readings +decorative +kijiji +confused +compiler +enlargement +eagles +bases +accused +campaigns +unity +conjunction +bride +defines +airports +instances +indigenous +begun +brunette +packets +anchor +socks +validation +parade +corruption +trigger +incentives +cholesterol +gathered +essex +slovenia +notified +differential +beaches +folders +dramatic +surfaces +terrible +routers +pendant +dresses +baptist +scientist +starsmerchant +hiring +clocks +arthritis +females +wallace +nevertheless +reflects +taxation +fever +cuisine +surely +practitioners +transcript +myspace +theorem +inflation +stylus +compounds +drums +contracting +arnold +structured +reasonably +chicks +cattle +radical +graduates +rover +recommends +controlling +treasure +reload +distributors +flame +levitra +tanks +assuming +monetary +elderly +arlington +particles +floating +extraordinary +indicating +bolivia +spell +hottest +stevens +coordinate +kuwait +exclusively +emily +alleged +limitation +widescreen +compile +webster +struck +illustration +plymouth +warnings +construct +inquiries +bridal +annex +inspiration +tribal +curious +affecting +freight +rebate +meetup +eclipse +sudan +downloading +shuttle +aggregate +stunning +cycles +affects +forecasts +detect +actively +ampland +complicated +fastest +butler +shopzilla +injured +decorating +payroll +cookbook +expressions +courier +uploaded +shakespeare +hints +collapse +americas +connectors +unlikely +conflicts +techno +beverage +tribute +wired +elvis +immune +latvia +travelers +forestry +barriers +rarely +infected +offerings +martha +genesis +barrier +argue +incorrect +trains +metals +bicycle +furnishings +letting +arise +guatemala +celtic +thereby +jamie +particle +perception +minerals +advise +humidity +bottles +boxing +bangkok +renaissance +pathology +ordinance +hughes +photographers +infections +jeffrey +chess +operates +brisbane +configured +survive +oscar +festivals +menus +possibilities +reveal +canal +amino +contributing +herbs +clinics +manitoba +analytical +missions +watson +lying +costumes +strict +saddam +circulation +drill +offense +bryan +protest +assumption +jerusalem +hobby +tries +transexuales +invention +nickname +technician +inline +executives +enquiries +washing +staffing +cognitive +exploring +trick +enquiry +closure +timber +intense +playlist +registrar +showers +supporters +ruling +steady +statutes +withdrawal +myers +drops +predicted +wider +saskatchewan +cancellation +plugins +enrolled +sensors +screw +ministers +publicly +hourly +blame +geneva +freebsd +veterinary +prostores +reseller +handed +suffered +intake +informal +relevance +incentive +butterfly +tucson +mechanics +heavily +swingers +fifty +headers +mistakes +numerical +uncle +defining +counting +reflection +accompanied +assure +invitation +devoted +princeton +jacob +sodium +randy +spirituality +hormone +meanwhile +proprietary +timothy +childrens +brick +naval +thumbzilla +medieval +porcelain +bridges +pichunter +captured +thehun +decent +casting +dayton +translated +shortly +cameron +columnists +carlos +donna +andreas +warrior +diploma +cabin +innocent +scanning +consensus +valium +copying +delivering +cordless +patricia +eddie +uganda +fired +journalism +trivia +adidas +perth +grammar +intention +syria +disagree +klein +harvey +tires +undertaken +hazard +retro +statewide +semiconductor +gregory +episodes +boolean +circular +anger +mainland +illustrations +suits +chances +interact +happiness +substantially +bizarre +glenn +auckland +olympics +fruits +identifier +ribbon +calculations +conducting +startup +suzuki +trinidad +kissing +handy +exempt +crops +reduces +accomplished +calculators +geometry +impression +slovakia +guild +correlation +gorgeous +capitol +dishes +barbados +chrysler +nervous +refuse +extends +fragrance +mcdonald +replica +plumbing +brussels +tribe +neighbors +trades +superb +transparent +trinity +charleston +handled +legends +champions +floors +selections +projectors +inappropriate +exhaust +comparing +shanghai +speaks +burton +vocational +davidson +copied +scotia +farming +gibson +pharmacies +roller +introducing +batch +organize +appreciated +alter +nicole +latino +ghana +edges +mixing +handles +skilled +fitted +albuquerque +harmony +distinguished +asthma +projected +assumptions +shareholders +twins +developmental +regulated +triangle +amend +anticipated +oriental +reward +windsor +zambia +completing +hydrogen +webshots +sprint +comparable +chick +advocate +confusion +copyrighted +inputs +warranties +genome +escorts +documented +thong +medal +paperbacks +coaches +vessels +harbour +walks +keyboards +knives +vulnerable +arrange +artistic +honors +booth +indie +reflected +unified +bones +breed +detector +ignored +polar +fallen +precise +sussex +respiratory +notifications +msgid +transexual +mainstream +invoice +evaluating +subcommittee +gather +maternity +backed +alfred +colonial +carey +motels +forming +embassy +journalists +danny +rebecca +slight +proceeds +indirect +amongst +foundations +msgstr +arrest +volleyball +adipex +horizon +deeply +toolbox +marina +liabilities +prizes +bosnia +browsers +decreased +patio +tolerance +surfing +creativity +lloyd +describing +optics +pursue +lightning +overcome +quotations +inspector +attract +brighton +beans +bookmarks +ellis +disable +snake +succeed +leonard +lending +reminder +searched +behavioral +riverside +bathrooms +plains +raymond +insights +abilities +initiated +sullivan +midwest +karaoke +lonely +nonprofit +lancaster +suspended +hereby +observe +julia +containers +attitudes +berry +collar +simultaneously +racial +integrate +bermuda +amanda +sociology +mobiles +screenshot +exhibitions +kelkoo +confident +retrieved +exhibits +officially +consortium +terrace +bacteria +replied +seafood +novels +recipients +ought +delicious +traditions +safely +finite +kidney +periodically +fixes +sends +durable +mazda +allied +throws +moisture +hungarian +roster +referring +symantec +spencer +wichita +nasdaq +uruguay +transform +timer +tablets +tuning +gotten +educators +tyler +futures +vegetable +verse +highs +humanities +independently +wanting +custody +scratch +launches +alignment +masturbating +henderson +britannica +ellen +competitors +rocket +bullet +towers +racks +nasty +visibility +latitude +consciousness +tumor +deposits +beverly +mistress +encounter +trustees +watts +duncan +reprints +bernard +resolutions +accessing +forty +tubes +attempted +midlands +priest +floyd +ronald +analysts +queue +trance +locale +nicholas +bundle +hammer +invasion +witnesses +runner +administered +notion +skins +mailed +fujitsu +spelling +arctic +exams +rewards +beneath +strengthen +defend +frederick +medicaid +infrared +seventh +welsh +belly +aggressive +advertisements +quarters +stolen +soonest +haiti +disturbed +determines +sculpture +naturals +motivation +lenders +pharmacology +fitting +fixtures +bloggers +agrees +passengers +quantities +petersburg +consistently +powerpoint +surplus +elder +sonic +obituaries +cheers +punishment +appreciation +subsequently +belarus +zoning +gravity +providence +thumb +restriction +incorporate +backgrounds +treasurer +guitars +essence +flooring +lightweight +ethiopia +mighty +athletes +humanity +transcription +holmes +complications +scholars +scripting +remembered +galaxy +chester +snapshot +caring +synthetic +segments +testament +dominant +twist +specifics +itunes +stomach +partially +buried +newbie +minimize +darwin +ranks +wilderness +debut +generations +tournaments +bradley +anatomy +sponsorship +headphones +fraction +proceeding +defects +volkswagen +uncertainty +breakdown +milton +marker +reconstruction +subsidiary +strengths +clarity +sandra +adelaide +encouraging +furnished +monaco +settled +folding +emirates +terrorists +airfare +comparisons +beneficial +distributions +vaccine +belize +viewpicture +promised +volvo +penny +robust +bookings +threatened +minolta +republicans +discusses +porter +jungle +responded +abstracts +ivory +alpine +prediction +pharmaceuticals +andale +fabulous +remix +alias +thesaurus +individually +battlefield +literally +newer +ecological +spice +implies +cooler +appraisal +consisting +maritime +periodic +submitting +overhead +ascii +prospect +shipment +breeding +citations +geographical +donor +mozambique +tension +trash +shapes +manor +envelope +diane +homeland +disclaimers +championships +excluded +andrea +breeds +rapids +disco +sheffield +bailey +endif +finishing +emotions +wellington +incoming +prospects +lexmark +cleaners +bulgarian +eternal +cashiers +aboriginal +remarkable +rotation +preventing +productive +boulevard +eugene +metric +compliant +minus +penalties +bennett +imagination +hotmail +refurbished +joshua +armenia +varied +grande +closest +activated +actress +conferencing +assign +armstrong +politicians +trackbacks +accommodate +tigers +aurora +slides +milan +premiere +lender +villages +shade +chorus +christine +rhythm +digit +argued +dietary +symphony +clarke +sudden +accepting +precipitation +marilyn +lions +findlaw +pools +lyric +claire +isolation +speeds +sustained +matched +approximate +carroll +rational +programmer +fighters +chambers +greetings +inherited +warming +incomplete +vocals +chronicle +fountain +chubby +grave +legitimate +biographies +burner +investigator +plaintiff +finnish +gentle +prisoners +deeper +muslims +mediterranean +nightlife +footage +howto +worthy +reveals +architects +saints +entrepreneur +carries +freelance +excessive +devon +screensaver +helena +saves +regarded +valuation +unexpected +cigarette +characteristic +marion +lobby +egyptian +tunisia +metallica +outlined +consequently +headline +treating +punch +appointments +gotta +cowboy +narrative +bahrain +enormous +karma +consist +betty +queens +academics +quantitative +lucas +screensavers +subdivision +tribes +defeat +clicks +distinction +honduras +naughty +hazards +insured +harper +livestock +mardi +exemption +tenant +sustainability +cabinets +tattoo +shake +algebra +shadows +holly +formatting +silly +nutritional +mercy +hartford +freely +marcus +sunrise +wrapping +nicaragua +weblogs +timeline +belongs +readily +affiliation +fence +nudist +infinite +diana +ensures +relatives +lindsay +legally +shame +satisfactory +revolutionary +bracelets +civilian +telephony +fatal +remedy +realtors +breathing +briefly +thickness +adjustments +graphical +genius +discussing +aerospace +fighter +meaningful +flesh +retreat +adapted +barely +wherever +estates +democrat +borough +maintains +failing +shortcuts +retained +voyeurweb +pamela +andrews +marble +extending +jesse +specifies +logitech +surrey +briefing +belkin +accreditation +blackberry +highland +meditation +modular +microphone +macedonia +combining +brandon +instrumental +giants +organizing +balloon +moderators +winston +solved +kazakhstan +hawaiian +standings +partition +invisible +gratuit +consoles +qatar +magnet +translations +porsche +cayman +jaguar +sheer +commodity +posing +kilometers +thanksgiving +hopkins +urgent +guarantees +infants +gothic +cylinder +witch +indication +congratulations +cohen +puppy +kathy +graphs +surround +cigarettes +revenge +expires +enemies +controllers +consultancy +finances +accepts +enjoying +conventions +patrol +smell +italiano +coordinates +carnival +roughly +sticker +promises +responding +physically +divide +stakeholders +hydrocodone +consecutive +cornell +satin +deserve +attempting +mailto +promo +representations +worried +tunes +garbage +competing +combines +bradford +phrases +peninsula +chelsea +boring +reynolds +accurately +speeches +reaches +schema +considers +catalogs +ministries +vacancies +quizzes +parliamentary +prefix +lucia +savannah +barrel +typing +nerve +planets +deficit +boulder +pointing +renew +coupled +myanmar +metadata +harold +circuits +floppy +texture +handbags +somerset +incurred +acknowledge +thoroughly +antigua +nottingham +thunder +caution +identifies +questionnaire +qualification +locks +modelling +namely +miniature +euros +interstate +pirates +aerial +consequence +rebel +systematic +perceived +origins +hired +makeup +textile +madagascar +nathan +tobago +presenting +troubleshooting +uzbekistan +indexes +centuries +magnitude +richardson +hindu +fragrances +vocabulary +licking +earthquake +fundraising +markers +weights +albania +geological +assessing +lasting +wicked +introduces +kills +roommate +webcams +pushed +webmasters +computational +acdbentity +participated +handhelds +answering +impressed +slope +reggae +failures +conspiracy +surname +theology +nails +evident +whats +rides +rehab +saturn +organizer +allergy +twisted +combinations +preceding +merit +enzyme +cumulative +zshops +planes +edmonton +tackle +disks +condo +pokemon +amplifier +ambien +arbitrary +prominent +retrieve +lexington +vernon +worldcat +titanium +fairy +builds +contacted +shaft +recorders +occasional +leslie +casio +deutsche +postings +innovations +kitty +postcards +drain +monte +fires +algeria +blessed +reviewing +cardiff +cornwall +favors +potato +panic +explicitly +sticks +leone +transsexual +citizenship +excuse +reforms +basement +onion +strand +sandwich +lawsuit +informative +girlfriend +bloomberg +cheque +hierarchy +influenced +banners +reject +abandoned +circles +italic +beats +merry +scuba +complement +passive +mauritius +valued +checklist +requesting +courage +verde +lauderdale +scenarios +gazette +hitachi +extraction +batman +elevation +hearings +coleman +utilization +beverages +calibration +efficiently +anaheim +textbook +dried +entertaining +prerequisite +luther +frontier +settle +stopping +refugees +knights +hypothesis +palmer +medicines +derby +peaceful +altered +pontiac +regression +doctrine +scenic +trainers +enhancements +renewable +intersection +passwords +sewing +consistency +collectors +conclude +recognised +munich +celebs +propose +azerbaijan +lighter +astrology +advisors +pavilion +tactics +trusts +occurring +supplemental +travelling +talented +annie +pillow +induction +derek +precisely +shorter +harley +spreading +provinces +relying +finals +paraguay +steal +parcel +refined +fifteen +widespread +incidence +fears +predict +boutique +acrylic +rolled +tuner +incidents +peterson +shannon +toddler +enhancing +flavor +alike +homeless +horrible +hungry +metallic +blocked +interference +warriors +palestine +listprice +cadillac +atmospheric +malawi +sagem +knowledgestorm +curtis +parental +referenced +strikes +lesser +publicity +marathon +proposition +pressing +gasoline +dressed +scout +belfast +dealt +niagara +warcraft +charms +catalyst +trader +bucks +allowance +denial +designation +thrown +prepaid +raises +duplicate +electro +criterion +badge +wrist +civilization +analyzed +vietnamese +heath +tremendous +ballot +lexus +varying +remedies +validity +trustee +weighted +angola +performs +plastics +realm +corrected +jenny +helmet +salaries +postcard +elephant +yemen +encountered +tsunami +scholar +nickel +internationally +surrounded +buses +expedia +geology +creatures +coating +commented +wallet +cleared +smilies +accomplish +boating +drainage +shakira +corners +broader +vegetarian +rouge +yeast +newfoundland +clearing +investigated +ambassador +coated +intend +stephanie +contacting +vegetation +findarticles +louise +kenny +specially +routines +hitting +yukon +beings +aquatic +reliance +habits +striking +infectious +podcasts +singh +gilbert +ferrari +continuity +brook +outputs +phenomenon +ensemble +insulin +assured +biblical +conscious +accent +mysimon +eleven +wives +ambient +utilize +mileage +prostate +adaptor +auburn +unlock +hyundai +pledge +vampire +angela +relates +nitrogen +xerox +merger +softball +referrals +differently +firewire +nextel +framing +organised +musician +blocking +rwanda +sorts +integrating +vsnet +limiting +dispatch +revisions +papua +restored +armor +riders +chargers +remark +dozens +varies +reasoning +rendered +picking +charitable +guards +annotated +convinced +openings +burlington +replacing +researcher +watershed +councils +occupations +acknowledged +kruger +pockets +granny +equilibrium +viral +inquire +pipes +characterized +laden +aruba +cottages +realtor +merge +privilege +edgar +develops +qualifying +chassis +dubai +estimation +pushing +fleece +pediatric +pierce +allan +dressing +techrepublic +sperm +filme +craps +frost +institutes +sally +yacht +tracy +prefers +drilling +brochures +breach +whale +traveller +appropriations +suspected +tomatoes +benchmark +beginners +instructors +highlighted +bedford +stationery +mustang +unauthorized +clusters +antibody +competent +momentum +wiring +pastor +calvin +shark +contributor +demonstrates +phases +grateful +emerald +gradually +laughing +grows +cliff +desirable +tract +ballet +journalist +abraham +bumper +afterwards +webpage +religions +garlic +hostels +shine +senegal +explosion +banned +wendy +briefs +signatures +diffs +mumbai +ozone +disciplines +daughters +conversations +radios +tariff +nvidia +opponent +pasta +simplified +muscles +serum +wrapped +swift +motherboard +runtime +inbox +focal +bibliographic +distant +champagne +decimal +deviation +superintendent +propecia +samba +hostel +housewives +employ +mongolia +penguin +magical +influences +inspections +irrigation +miracle +manually +reprint +hydraulic +centered +robertson +yearly +penetration +wound +belle +conviction +omissions +writings +hamburg +retrieval +qualities +cindy +fathers +charging +marvel +lined +prototype +importantly +petite +apparatus +terrain +explaining +strips +gossip +rangers +nomination +empirical +rotary +dependence +discrete +beginner +boxed +sexuality +polyester +cubic +commitments +suggesting +sapphire +kinase +skirts +remainder +crawford +labeled +privileges +televisions +specializing +marking +commodities +serbia +sheriff +griffin +declined +guyana +spies +neighbor +motorcycles +elect +highways +thinkpad +concentrate +intimate +reproductive +preston +deadly +bunny +chevy +molecules +rounds +longest +refrigerator +tions +intervals +sentences +dentists +exclusion +workstation +holocaust +flyer +dosage +receivers +customise +disposition +variance +navigator +investigators +cameroon +baking +marijuana +adaptive +computed +needle +baths +cathedral +brakes +nirvana +fairfield +invision +sticky +destiny +generous +madness +emacs +climb +blowing +fascinating +landscapes +heated +lafayette +jackie +computation +cardiovascular +sparc +cardiac +salvation +dover +adrian +predictions +accompanying +vatican +brutal +learners +selective +arbitration +configuring +token +editorials +sacrifice +seekers +removable +convergence +yields +gibraltar +suited +numeric +anthropology +skating +kinda +aberdeen +emperor +malpractice +dylan +belts +blacks +educated +rebates +reporters +burke +proudly +necessity +rendering +inserted +pulling +basename +obesity +curves +suburban +touring +clara +vertex +hepatitis +nationally +tomato +andorra +waterproof +expired +travels +flush +waiver +specialties +hayes +humanitarian +invitations +functioning +delight +survivor +garcia +cingular +economies +alexandria +bacterial +moses +counted +undertake +declare +continuously +johns +valves +impaired +achievements +donors +jewel +teddy +convertible +teaches +ventures +bufing +stranger +tragedy +julian +dryer +painful +velvet +tribunal +ruled +pensions +prayers +funky +secretariat +nowhere +paragraphs +joins +adolescent +nominations +wesley +lately +cancelled +scary +mattress +mpegs +brunei +likewise +banana +introductory +slovak +cakes +reservoir +occurrence +mixer +remind +worcester +sbjct +demographic +charming +tooth +disciplinary +annoying +respected +stays +disclose +affair +drove +washer +upset +restrict +springer +beside +mines +portraits +rebound +logan +mentor +interpreted +evaluations +fought +baghdad +elimination +metres +hypothetical +immigrants +complimentary +helicopter +pencil +freeze +performer +titled +commissions +sphere +powerseller +ratios +concord +graduated +endorsed +surprising +walnut +lance +ladder +italia +unnecessary +dramatically +liberia +sherman +maximize +hansen +senators +workout +yugoslavia +bleeding +characterization +colon +likelihood +lanes +purse +fundamentals +contamination +endangered +compromise +masturbation +optimize +stating +caroline +expiration +namespace +align +peripheral +bless +engaging +negotiation +crest +opponents +triumph +nominated +confidentiality +electoral +changelog +welding +deferred +alternatively +alloy +condos +plots +polished +gently +greensboro +tulsa +locking +casey +controversial +draws +fridge +blanket +bloom +simpsons +elliott +recovered +fraser +justify +upgrading +blades +loops +surge +frontpage +trauma +tahoe +advert +possess +demanding +defensive +flashers +subaru +forbidden +vanilla +programmers +monitored +installations +deutschland +picnic +souls +arrivals +spank +practitioner +motivated +smithsonian +hollow +vault +securely +examining +fioricet +groove +revelation +pursuit +delegation +wires +dictionaries +mails +backing +greenhouse +sleeps +blake +transparency +travis +endless +figured +orbit +currencies +niger +bacon +survivors +positioning +heater +colony +cannon +circus +promoted +forbes +moldova +descending +paxil +spine +trout +enclosed +temporarily +cooked +thriller +transmit +apnic +fatty +gerald +pressed +frequencies +scanned +reflections +hunger +mariah +municipality +joyce +detective +surgeon +cement +experiencing +fireplace +endorsement +planners +disputes +textiles +missile +intranet +closes +psychiatry +persistent +deborah +marco +assists +summaries +gabriel +auditor +aquarium +violin +prophet +bracket +looksmart +isaac +oxide +magnificent +colleague +naples +promptly +modems +adaptation +harmful +paintball +prozac +sexually +enclosure +dividend +newark +glucose +phantom +playback +supervisors +westminster +turtle +distances +absorption +treasures +warned +neural +fossil +hometown +badly +transcripts +apollo +disappointed +persian +continually +communist +collectible +handmade +greene +entrepreneurs +robots +grenada +creations +scoop +acquisitions +earning +mailman +sanyo +nested +biodiversity +excitement +somalia +movers +verbal +blink +presently +carlo +workflow +mysterious +novelty +bryant +tiles +voyuer +librarian +subsidiaries +switched +stockholm +tamil +garmin +fuzzy +indonesian +grams +therapist +richards +budgets +toolkit +promising +relaxation +render +carmen +thereafter +hardwood +erotica +temporal +forge +commissioners +dense +brave +forwarding +awful +nightmare +airplane +reductions +southampton +istanbul +impose +organisms +telescope +viewers +asbestos +portsmouth +meyer +enters +savage +advancement +harassment +willow +resumes +throwing +existed +generators +wagon +barbie +favour +knock +generates +potatoes +thorough +replication +inexpensive +receptors +peers +roland +optimum +interventions +quilt +huntington +creature +mounts +syracuse +internship +refresh +aluminium +snowboard +beastality +webcast +michel +evanescence +subtle +coordinated +notre +shipments +maldives +stripes +firmware +antarctica +shepherd +canberra +cradle +chancellor +mambo +flour +controversy +legendary +sympathy +choir +avoiding +beautifully +blond +expects +jumping +fabrics +antibodies +polymer +hygiene +poultry +virtue +burst +examinations +surgeons +bouquet +immunology +promotes +mandate +wiley +departmental +corpus +johnston +terminology +gentleman +fibre +reproduce +convicted +shades +indices +roommates +adware +threatening +spokesman +zoloft +activists +frankfurt +prisoner +daisy +halifax +encourages +ultram +cursor +assembled +earliest +donated +stuffed +restructuring +insects +terminals +crude +morrison +maiden +simulations +sufficiently +examines +viking +myrtle +bored +cleanup +conditional +crossword +bother +budapest +conceptual +knitting +attacked +bhutan +liechtenstein +mating +compute +redhead +arrives +translator +automobiles +tractor +allah +continent +unwrap +fares +longitude +resist +challenged +telecharger +hoped +safer +insertion +instrumentation +wagner +constraint +groundwater +touched +strengthening +cologne +wishing +ranger +smallest +insulation +newman +marsh +ricky +scared +theta +infringement +subjective +monsters +asylum +lightbox +robbie +stake +cocktail +outlets +swaziland +varieties +arbor +mediawiki +configurations +poison diff --git a/contrib/python/moth/mistune.py b/contrib/python/moth/mistune.py new file mode 100644 index 0000000..a81c4c1 --- /dev/null +++ b/contrib/python/moth/mistune.py @@ -0,0 +1,1190 @@ +# coding: utf-8 +"""mistune + ~~~~~~~ + + The fastest markdown parser in pure Python with renderer feature. + + Copyright (c) 2014 - 2015, Hsiaoming Yang + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the creator nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +""" + +import re +import inspect + +__version__ = '0.7.3' +__author__ = 'Hsiaoming Yang ' +__all__ = [ + 'BlockGrammar', 'BlockLexer', + 'InlineGrammar', 'InlineLexer', + 'Renderer', 'Markdown', + 'markdown', 'escape', +] + + +_key_pattern = re.compile(r'\s+') +_nonalpha_pattern = re.compile(r'\W') +_escape_pattern = re.compile(r'&(?!#?\w+;)') +_newline_pattern = re.compile(r'\r\n|\r') +_block_quote_leading_pattern = re.compile(r'^ *> ?', flags=re.M) +_block_code_leading_pattern = re.compile(r'^ {4}', re.M) +_inline_tags = [ + 'a', 'em', 'strong', 'small', 's', 'cite', 'q', 'dfn', 'abbr', 'data', + 'time', 'code', 'var', 'samp', 'kbd', 'sub', 'sup', 'i', 'b', 'u', 'mark', + 'ruby', 'rt', 'rp', 'bdi', 'bdo', 'span', 'br', 'wbr', 'ins', 'del', + 'img', 'font', +] +_pre_tags = ['pre', 'script', 'style'] +_valid_end = r'(?!:/|[^\w\s@]*@)\b' +_valid_attr = r'''\s*[a-zA-Z\-](?:\=(?:"[^"]*"|'[^']*'|\d+))*''' +_block_tag = r'(?!(?:%s)\b)\w+%s' % ('|'.join(_inline_tags), _valid_end) +_scheme_blacklist = ('javascript:', 'vbscript:') + + +def _pure_pattern(regex): + pattern = regex.pattern + if pattern.startswith('^'): + pattern = pattern[1:] + return pattern + + +def _keyify(key): + return _key_pattern.sub(' ', key.lower()) + + +def escape(text, quote=False, smart_amp=True): + """Replace special characters "&", "<" and ">" to HTML-safe sequences. + + The original cgi.escape will always escape "&", but you can control + this one for a smart escape amp. + + :param quote: if set to True, " and ' will be escaped. + :param smart_amp: if set to False, & will always be escaped. + """ + if smart_amp: + text = _escape_pattern.sub('&', text) + else: + text = text.replace('&', '&') + text = text.replace('<', '<') + text = text.replace('>', '>') + if quote: + text = text.replace('"', '"') + text = text.replace("'", ''') + return text + + +def escape_link(url): + """Remove dangerous URL schemes like javascript: and escape afterwards.""" + lower_url = url.lower().strip('\x00\x1a \n\r\t') + for scheme in _scheme_blacklist: + if lower_url.startswith(scheme): + return '' + return escape(url, quote=True, smart_amp=False) + + +def preprocessing(text, tab=4): + text = _newline_pattern.sub('\n', text) + text = text.expandtabs(tab) + text = text.replace('\u00a0', ' ') + text = text.replace('\u2424', '\n') + pattern = re.compile(r'^ +$', re.M) + return pattern.sub('', text) + + +class BlockGrammar(object): + """Grammars for block level tokens.""" + + def_links = re.compile( + r'^ *\[([^^\]]+)\]: *' # [key]: + r']+)>?' # or link + r'(?: +["(]([^\n]+)[")])? *(?:\n+|$)' + ) + def_footnotes = re.compile( + r'^\[\^([^\]]+)\]: *(' + r'[^\n]*(?:\n+|$)' # [^key]: + r'(?: {1,}[^\n]*(?:\n+|$))*' + r')' + ) + + newline = re.compile(r'^\n+') + block_code = re.compile(r'^( {4}[^\n]+\n*)+') + fences = re.compile( + r'^ *(`{3,}|~{3,}) *(\S+)? *\n' # ```lang + r'([\s\S]+?)\s*' + r'\1 *(?:\n+|$)' # ``` + ) + hrule = re.compile(r'^ {0,3}[-*_](?: *[-*_]){2,} *(?:\n+|$)') + heading = re.compile(r'^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)') + lheading = re.compile(r'^([^\n]+)\n *(=|-)+ *(?:\n+|$)') + block_quote = re.compile(r'^( *>[^\n]+(\n[^\n]+)*\n*)+') + list_block = re.compile( + r'^( *)([*+-]|\d+\.) [\s\S]+?' + r'(?:' + r'\n+(?=\1?(?:[-*_] *){3,}(?:\n+|$))' # hrule + r'|\n+(?=%s)' # def links + r'|\n+(?=%s)' # def footnotes + r'|\n{2,}' + r'(?! )' + r'(?!\1(?:[*+-]|\d+\.) )\n*' + r'|' + r'\s*$)' % ( + _pure_pattern(def_links), + _pure_pattern(def_footnotes), + ) + ) + list_item = re.compile( + r'^(( *)(?:[*+-]|\d+\.) [^\n]*' + r'(?:\n(?!\2(?:[*+-]|\d+\.) )[^\n]*)*)', + flags=re.M + ) + list_bullet = re.compile(r'^ *(?:[*+-]|\d+\.) +') + paragraph = re.compile( + r'^((?:[^\n]+\n?(?!' + r'%s|%s|%s|%s|%s|%s|%s|%s|%s' + r'))+)\n*' % ( + _pure_pattern(fences).replace(r'\1', r'\2'), + _pure_pattern(list_block).replace(r'\1', r'\3'), + _pure_pattern(hrule), + _pure_pattern(heading), + _pure_pattern(lheading), + _pure_pattern(block_quote), + _pure_pattern(def_links), + _pure_pattern(def_footnotes), + '<' + _block_tag, + ) + ) + block_html = re.compile( + r'^ *(?:%s|%s|%s) *(?:\n{2,}|\s*$)' % ( + r'', + r'<(%s)((?:%s)*?)>([\s\S]*?)<\/\1>' % (_block_tag, _valid_attr), + r'<%s(?:%s)*?\s*\/?>' % (_block_tag, _valid_attr), + ) + ) + table = re.compile( + r'^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*' + ) + nptable = re.compile( + r'^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*' + ) + text = re.compile(r'^[^\n]+') + + +class BlockLexer(object): + """Block level lexer for block grammars.""" + grammar_class = BlockGrammar + + default_rules = [ + 'newline', 'hrule', 'block_code', 'fences', 'heading', + 'nptable', 'lheading', 'block_quote', + 'list_block', 'block_html', 'def_links', + 'def_footnotes', 'table', 'paragraph', 'text' + ] + + list_rules = ( + 'newline', 'block_code', 'fences', 'lheading', 'hrule', + 'block_quote', 'list_block', 'block_html', 'text', + ) + + footnote_rules = ( + 'newline', 'block_code', 'fences', 'heading', + 'nptable', 'lheading', 'hrule', 'block_quote', + 'list_block', 'block_html', 'table', 'paragraph', 'text' + ) + + def __init__(self, rules=None, **kwargs): + self.tokens = [] + self.def_links = {} + self.def_footnotes = {} + + if not rules: + rules = self.grammar_class() + + self.rules = rules + + def __call__(self, text, rules=None): + return self.parse(text, rules) + + def parse(self, text, rules=None): + text = text.rstrip('\n') + + if not rules: + rules = self.default_rules + + def manipulate(text): + for key in rules: + rule = getattr(self.rules, key) + m = rule.match(text) + if not m: + continue + getattr(self, 'parse_%s' % key)(m) + return m + return False # pragma: no cover + + while text: + m = manipulate(text) + if m is not False: + text = text[len(m.group(0)):] + continue + if text: # pragma: no cover + raise RuntimeError('Infinite loop at: %s' % text) + return self.tokens + + def parse_newline(self, m): + length = len(m.group(0)) + if length > 1: + self.tokens.append({'type': 'newline'}) + + def parse_block_code(self, m): + # clean leading whitespace + code = _block_code_leading_pattern.sub('', m.group(0)) + self.tokens.append({ + 'type': 'code', + 'lang': None, + 'text': code, + }) + + def parse_fences(self, m): + self.tokens.append({ + 'type': 'code', + 'lang': m.group(2), + 'text': m.group(3), + }) + + def parse_heading(self, m): + self.tokens.append({ + 'type': 'heading', + 'level': len(m.group(1)), + 'text': m.group(2), + }) + + def parse_lheading(self, m): + """Parse setext heading.""" + self.tokens.append({ + 'type': 'heading', + 'level': 1 if m.group(2) == '=' else 2, + 'text': m.group(1), + }) + + def parse_hrule(self, m): + self.tokens.append({'type': 'hrule'}) + + def parse_list_block(self, m): + bull = m.group(2) + self.tokens.append({ + 'type': 'list_start', + 'ordered': '.' in bull, + }) + cap = m.group(0) + self._process_list_item(cap, bull) + self.tokens.append({'type': 'list_end'}) + + def _process_list_item(self, cap, bull): + cap = self.rules.list_item.findall(cap) + + _next = False + length = len(cap) + + for i in range(length): + item = cap[i][0] + + # remove the bullet + space = len(item) + item = self.rules.list_bullet.sub('', item) + + # outdent + if '\n ' in item: + space = space - len(item) + pattern = re.compile(r'^ {1,%d}' % space, flags=re.M) + item = pattern.sub('', item) + + # determine whether item is loose or not + loose = _next + if not loose and re.search(r'\n\n(?!\s*$)', item): + loose = True + + rest = len(item) + if i != length - 1 and rest: + _next = item[rest - 1] == '\n' + if not loose: + loose = _next + + if loose: + t = 'loose_item_start' + else: + t = 'list_item_start' + + self.tokens.append({'type': t}) + # recurse + self.parse(item, self.list_rules) + self.tokens.append({'type': 'list_item_end'}) + + def parse_block_quote(self, m): + self.tokens.append({'type': 'block_quote_start'}) + # clean leading > + cap = _block_quote_leading_pattern.sub('', m.group(0)) + self.parse(cap) + self.tokens.append({'type': 'block_quote_end'}) + + def parse_def_links(self, m): + key = _keyify(m.group(1)) + self.def_links[key] = { + 'link': m.group(2), + 'title': m.group(3), + } + + def parse_def_footnotes(self, m): + key = _keyify(m.group(1)) + if key in self.def_footnotes: + # footnote is already defined + return + + self.def_footnotes[key] = 0 + + self.tokens.append({ + 'type': 'footnote_start', + 'key': key, + }) + + text = m.group(2) + + if '\n' in text: + lines = text.split('\n') + whitespace = None + for line in lines[1:]: + space = len(line) - len(line.lstrip()) + if space and (not whitespace or space < whitespace): + whitespace = space + newlines = [lines[0]] + for line in lines[1:]: + newlines.append(line[whitespace:]) + text = '\n'.join(newlines) + + self.parse(text, self.footnote_rules) + + self.tokens.append({ + 'type': 'footnote_end', + 'key': key, + }) + + def parse_table(self, m): + item = self._process_table(m) + + cells = re.sub(r'(?: *\| *)?\n$', '', m.group(3)) + cells = cells.split('\n') + for i, v in enumerate(cells): + v = re.sub(r'^ *\| *| *\| *$', '', v) + cells[i] = re.split(r' *\| *', v) + + item['cells'] = cells + self.tokens.append(item) + + def parse_nptable(self, m): + item = self._process_table(m) + + cells = re.sub(r'\n$', '', m.group(3)) + cells = cells.split('\n') + for i, v in enumerate(cells): + cells[i] = re.split(r' *\| *', v) + + item['cells'] = cells + self.tokens.append(item) + + def _process_table(self, m): + header = re.sub(r'^ *| *\| *$', '', m.group(1)) + header = re.split(r' *\| *', header) + align = re.sub(r' *|\| *$', '', m.group(2)) + align = re.split(r' *\| *', align) + + for i, v in enumerate(align): + if re.search(r'^ *-+: *$', v): + align[i] = 'right' + elif re.search(r'^ *:-+: *$', v): + align[i] = 'center' + elif re.search(r'^ *:-+ *$', v): + align[i] = 'left' + else: + align[i] = None + + item = { + 'type': 'table', + 'header': header, + 'align': align, + } + return item + + def parse_block_html(self, m): + tag = m.group(1) + if not tag: + text = m.group(0) + self.tokens.append({ + 'type': 'close_html', + 'text': text + }) + else: + attr = m.group(2) + text = m.group(3) + self.tokens.append({ + 'type': 'open_html', + 'tag': tag, + 'extra': attr, + 'text': text + }) + + def parse_paragraph(self, m): + text = m.group(1).rstrip('\n') + self.tokens.append({'type': 'paragraph', 'text': text}) + + def parse_text(self, m): + text = m.group(0) + self.tokens.append({'type': 'text', 'text': text}) + + +class InlineGrammar(object): + """Grammars for inline level tokens.""" + + escape = re.compile(r'^\\([\\`*{}\[\]()#+\-.!_>~|])') # \* \+ \! .... + inline_html = re.compile( + r'^(?:%s|%s|%s)' % ( + r'', + r'<(\w+%s)((?:%s)*?)\s*>([\s\S]*?)<\/\1>' % (_valid_end, _valid_attr), + r'<\w+%s(?:%s)*?\s*\/?>' % (_valid_end, _valid_attr), + ) + ) + autolink = re.compile(r'^<([^ >]+(@|:)[^ >]+)>') + link = re.compile( + r'^!?\[(' + r'(?:\[[^^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*' + r')\]\(' + r'''\s*(<)?([\s\S]*?)(?(2)>)(?:\s+['"]([\s\S]*?)['"])?\s*''' + r'\)' + ) + reflink = re.compile( + r'^!?\[(' + r'(?:\[[^^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*' + r')\]\s*\[([^^\]]*)\]' + ) + nolink = re.compile(r'^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]') + url = re.compile(r'''^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])''') + double_emphasis = re.compile( + r'^_{2}([\s\S]+?)_{2}(?!_)' # __word__ + r'|' + r'^\*{2}([\s\S]+?)\*{2}(?!\*)' # **word** + ) + emphasis = re.compile( + r'^\b_((?:__|[^_])+?)_\b' # _word_ + r'|' + r'^\*((?:\*\*|[^\*])+?)\*(?!\*)' # *word* + ) + code = re.compile(r'^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)') # `code` + linebreak = re.compile(r'^ {2,}\n(?!\s*$)') + strikethrough = re.compile(r'^~~(?=\S)([\s\S]*?\S)~~') # ~~word~~ + footnote = re.compile(r'^\[\^([^\]]+)\]') + text = re.compile(r'^[\s\S]+?(?=[\\%s' % (tag, extra, text, tag) + else: + html = m.group(0) + return self.renderer.inline_html(html) + + def output_footnote(self, m): + key = _keyify(m.group(1)) + if key not in self.footnotes: + return None + if self.footnotes[key]: + return None + self.footnote_index += 1 + self.footnotes[key] = self.footnote_index + return self.renderer.footnote_ref(key, self.footnote_index) + + def output_link(self, m): + return self._process_link(m, m.group(3), m.group(4)) + + def output_reflink(self, m): + key = _keyify(m.group(2) or m.group(1)) + if key not in self.links: + return None + ret = self.links[key] + return self._process_link(m, ret['link'], ret['title']) + + def output_nolink(self, m): + key = _keyify(m.group(1)) + if key not in self.links: + return None + ret = self.links[key] + return self._process_link(m, ret['link'], ret['title']) + + def _process_link(self, m, link, title=None): + line = m.group(0) + text = m.group(1) + if line[0] == '!': + return self.renderer.image(link, title, text) + + self._in_link = True + text = self.output(text) + self._in_link = False + return self.renderer.link(link, title, text) + + def output_double_emphasis(self, m): + text = m.group(2) or m.group(1) + text = self.output(text) + return self.renderer.double_emphasis(text) + + def output_emphasis(self, m): + text = m.group(2) or m.group(1) + text = self.output(text) + return self.renderer.emphasis(text) + + def output_code(self, m): + text = m.group(2) + return self.renderer.codespan(text) + + def output_linebreak(self, m): + return self.renderer.linebreak() + + def output_strikethrough(self, m): + text = self.output(m.group(1)) + return self.renderer.strikethrough(text) + + def output_text(self, m): + text = m.group(0) + return self.renderer.text(text) + + +class Renderer(object): + """The default HTML renderer for rendering Markdown. + """ + + def __init__(self, **kwargs): + self.options = kwargs + + def placeholder(self): + """Returns the default, empty output value for the renderer. + + All renderer methods use the '+=' operator to append to this value. + Default is a string so rendering HTML can build up a result string with + the rendered Markdown. + + Can be overridden by Renderer subclasses to be types like an empty + list, allowing the renderer to create a tree-like structure to + represent the document (which can then be reprocessed later into a + separate format like docx or pdf). + """ + return '' + + def block_code(self, code, lang=None): + """Rendering block level code. ``pre > code``. + + :param code: text content of the code block. + :param lang: language of the given code. + """ + code = code.rstrip('\n') + if not lang: + code = escape(code, smart_amp=False) + return '
%s\n
\n' % code + code = escape(code, quote=True, smart_amp=False) + return '
%s\n
\n' % (lang, code) + + def block_quote(self, text): + """Rendering
with the given text. + + :param text: text content of the blockquote. + """ + return '
%s\n
\n' % text.rstrip('\n') + + def block_html(self, html): + """Rendering block level pure html content. + + :param html: text content of the html snippet. + """ + if self.options.get('skip_style') and \ + html.lower().startswith('`` ``

``. + + :param text: rendered text content for the header. + :param level: a number for the header level, for example: 1. + :param raw: raw text content of the header. + """ + return '%s\n' % (level, text, level) + + def hrule(self): + """Rendering method for ``
`` tag.""" + if self.options.get('use_xhtml'): + return '
\n' + return '
\n' + + def list(self, body, ordered=True): + """Rendering list tags like ``
    `` and ``
      ``. + + :param body: body contents of the list. + :param ordered: whether this list is ordered or not. + """ + tag = 'ul' + if ordered: + tag = 'ol' + return '<%s>\n%s\n' % (tag, body, tag) + + def list_item(self, text): + """Rendering list item snippet. Like ``
    1. ``.""" + return '
    2. %s
    3. \n' % text + + def paragraph(self, text): + """Rendering paragraph tags. Like ``

      ``.""" + return '

      %s

      \n' % text.strip(' ') + + def table(self, header, body): + """Rendering table element. Wrap header and body in it. + + :param header: header part of the table. + :param body: body part of the table. + """ + return ( + '\n%s\n' + '\n%s\n
      \n' + ) % (header, body) + + def table_row(self, content): + """Rendering a table row. Like ````. + + :param content: content of current table row. + """ + return '\n%s\n' % content + + def table_cell(self, content, **flags): + """Rendering a table cell. Like ```` ````. + + :param content: content of current table cell. + :param header: whether this is header or not. + :param align: align of current table cell. + """ + if flags['header']: + tag = 'th' + else: + tag = 'td' + align = flags['align'] + if not align: + return '<%s>%s\n' % (tag, content, tag) + return '<%s style="text-align:%s">%s\n' % ( + tag, align, content, tag + ) + + def double_emphasis(self, text): + """Rendering **strong** text. + + :param text: text content for emphasis. + """ + return '%s' % text + + def emphasis(self, text): + """Rendering *emphasis* text. + + :param text: text content for emphasis. + """ + return '%s' % text + + def codespan(self, text): + """Rendering inline `code` text. + + :param text: text content for inline code. + """ + text = escape(text.rstrip(), smart_amp=False) + return '%s' % text + + def linebreak(self): + """Rendering line break like ``
      ``.""" + if self.options.get('use_xhtml'): + return '
      \n' + return '
      \n' + + def strikethrough(self, text): + """Rendering ~~strikethrough~~ text. + + :param text: text content for strikethrough. + """ + return '%s' % text + + def text(self, text): + """Rendering unformatted text. + + :param text: text content. + """ + return escape(text) + + def escape(self, text): + """Rendering escape sequence. + + :param text: text content. + """ + return escape(text) + + def autolink(self, link, is_email=False): + """Rendering a given link or email address. + + :param link: link content or email address. + :param is_email: whether this is an email or not. + """ + text = link = escape(link) + if is_email: + link = 'mailto:%s' % link + return '%s' % (link, text) + + def link(self, link, title, text): + """Rendering a given link with content and title. + + :param link: href link for ```` tag. + :param title: title content for `title` attribute. + :param text: text content for description. + """ + link = escape_link(link) + if not title: + return '%s' % (link, text) + title = escape(title, quote=True) + return '%s' % (link, title, text) + + def image(self, src, title, text): + """Rendering a image with title and text. + + :param src: source link of the image. + :param title: title text of the image. + :param text: alt text of the image. + """ + src = escape_link(src) + text = escape(text, quote=True) + if title: + title = escape(title, quote=True) + html = '%s' % html + return '%s>' % html + + def inline_html(self, html): + """Rendering span level pure html content. + + :param html: text content of the html snippet. + """ + if self.options.get('escape'): + return escape(html) + return html + + def newline(self): + """Rendering newline element.""" + return '' + + def footnote_ref(self, key, index): + """Rendering the ref anchor of a footnote. + + :param key: identity key for the footnote. + :param index: the index count of current footnote. + """ + html = ( + '' + '%d' + ) % (escape(key), escape(key), index) + return html + + def footnote_item(self, key, text): + """Rendering a footnote item. + + :param key: identity key for the footnote. + :param text: text content of the footnote. + """ + back = ( + '' + ) % escape(key) + text = text.rstrip() + if text.endswith('

      '): + text = re.sub(r'<\/p>$', r'%s

      ' % back, text) + else: + text = '%s

      %s

      ' % (text, back) + html = '
    4. %s
    5. \n' % (escape(key), text) + return html + + def footnotes(self, text): + """Wrapper for all footnotes. + + :param text: contents of all footnotes. + """ + html = '
      \n%s
        %s
      \n
      \n' + return html % (self.hrule(), text) + + +class Markdown(object): + """The Markdown parser. + + :param renderer: An instance of ``Renderer``. + :param inline: An inline lexer class or instance. + :param block: A block lexer class or instance. + """ + def __init__(self, renderer=None, inline=None, block=None, **kwargs): + if not renderer: + renderer = Renderer(**kwargs) + else: + kwargs.update(renderer.options) + + self.renderer = renderer + + if inline and inspect.isclass(inline): + inline = inline(renderer, **kwargs) + if block and inspect.isclass(block): + block = block(**kwargs) + + if inline: + self.inline = inline + else: + self.inline = InlineLexer(renderer, **kwargs) + + self.block = block or BlockLexer(BlockGrammar()) + self.footnotes = [] + self.tokens = [] + + # detect if it should parse text in block html + self._parse_block_html = kwargs.get('parse_block_html') + + def __call__(self, text): + return self.parse(text) + + def render(self, text): + """Render the Markdown text. + + :param text: markdown formatted text content. + """ + return self.parse(text) + + def parse(self, text): + out = self.output(preprocessing(text)) + + keys = self.block.def_footnotes + + # reset block + self.block.def_links = {} + self.block.def_footnotes = {} + + # reset inline + self.inline.links = {} + self.inline.footnotes = {} + + if not self.footnotes: + return out + + footnotes = filter(lambda o: keys.get(o['key']), self.footnotes) + self.footnotes = sorted( + footnotes, key=lambda o: keys.get(o['key']), reverse=True + ) + + body = self.renderer.placeholder() + while self.footnotes: + note = self.footnotes.pop() + body += self.renderer.footnote_item( + note['key'], note['text'] + ) + + out += self.renderer.footnotes(body) + return out + + def pop(self): + if not self.tokens: + return None + self.token = self.tokens.pop() + return self.token + + def peek(self): + if self.tokens: + return self.tokens[-1] + return None # pragma: no cover + + def output(self, text, rules=None): + self.tokens = self.block(text, rules) + self.tokens.reverse() + + self.inline.setup(self.block.def_links, self.block.def_footnotes) + + out = self.renderer.placeholder() + while self.pop(): + out += self.tok() + return out + + def tok(self): + t = self.token['type'] + + # sepcial cases + if t.endswith('_start'): + t = t[:-6] + + return getattr(self, 'output_%s' % t)() + + def tok_text(self): + text = self.token['text'] + while self.peek()['type'] == 'text': + text += '\n' + self.pop()['text'] + return self.inline(text) + + def output_newline(self): + return self.renderer.newline() + + def output_hrule(self): + return self.renderer.hrule() + + def output_heading(self): + return self.renderer.header( + self.inline(self.token['text']), + self.token['level'], + self.token['text'], + ) + + def output_code(self): + return self.renderer.block_code( + self.token['text'], self.token['lang'] + ) + + def output_table(self): + aligns = self.token['align'] + aligns_length = len(aligns) + cell = self.renderer.placeholder() + + # header part + header = self.renderer.placeholder() + for i, value in enumerate(self.token['header']): + align = aligns[i] if i < aligns_length else None + flags = {'header': True, 'align': align} + cell += self.renderer.table_cell(self.inline(value), **flags) + + header += self.renderer.table_row(cell) + + # body part + body = self.renderer.placeholder() + for i, row in enumerate(self.token['cells']): + cell = self.renderer.placeholder() + for j, value in enumerate(row): + align = aligns[j] if j < aligns_length else None + flags = {'header': False, 'align': align} + cell += self.renderer.table_cell(self.inline(value), **flags) + body += self.renderer.table_row(cell) + + return self.renderer.table(header, body) + + def output_block_quote(self): + body = self.renderer.placeholder() + while self.pop()['type'] != 'block_quote_end': + body += self.tok() + return self.renderer.block_quote(body) + + def output_list(self): + ordered = self.token['ordered'] + body = self.renderer.placeholder() + while self.pop()['type'] != 'list_end': + body += self.tok() + return self.renderer.list(body, ordered) + + def output_list_item(self): + body = self.renderer.placeholder() + while self.pop()['type'] != 'list_item_end': + if self.token['type'] == 'text': + body += self.tok_text() + else: + body += self.tok() + + return self.renderer.list_item(body) + + def output_loose_item(self): + body = self.renderer.placeholder() + while self.pop()['type'] != 'list_item_end': + body += self.tok() + return self.renderer.list_item(body) + + def output_footnote(self): + self.inline._in_footnote = True + body = self.renderer.placeholder() + key = self.token['key'] + while self.pop()['type'] != 'footnote_end': + body += self.tok() + self.footnotes.append({'key': key, 'text': body}) + self.inline._in_footnote = False + return self.renderer.placeholder() + + def output_close_html(self): + text = self.token['text'] + return self.renderer.block_html(text) + + def output_open_html(self): + text = self.token['text'] + tag = self.token['tag'] + if self._parse_block_html and tag not in _pre_tags: + text = self.inline(text, rules=self.inline.inline_html_rules) + extra = self.token.get('extra') or '' + html = '<%s%s>%s' % (tag, extra, text, tag) + return self.renderer.block_html(html) + + def output_paragraph(self): + return self.renderer.paragraph(self.inline(self.token['text'])) + + def output_text(self): + return self.renderer.paragraph(self.tok_text()) + + +def markdown(text, escape=True, **kwargs): + """Render markdown formatted text to html. + + :param text: markdown formatted text content. + :param escape: if set to False, all html tags will not be escaped. + :param use_xhtml: output with xhtml tags. + :param hard_wrap: if set to True, it will use the GFM line breaks feature. + :param parse_block_html: parse text only in block level html. + :param parse_inline_html: parse text only in inline level html. + """ + return Markdown(escape=escape, **kwargs)(text) diff --git a/contrib/python/moth/moth.py b/contrib/python/moth/moth.py new file mode 100644 index 0000000..e0a6209 --- /dev/null +++ b/contrib/python/moth/moth.py @@ -0,0 +1,456 @@ +#!/usr/bin/python3 + +import argparse +import contextlib +import copy +import glob +import hashlib +import html +import io +import importlib.machinery +import logging +import os +import random +import string +import sys +import tempfile +import shlex +import yaml + +from . import mistune + +messageChars = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + +LOGGER = logging.getLogger(__name__) + +def djb2hash(str): + h = 5381 + for c in str.encode("utf-8"): + h = ((h * 33) + c) & 0xffffffff + return h + +@contextlib.contextmanager +def pushd(newdir): + curdir = os.getcwd() + LOGGER.debug("Attempting to chdir from %s to %s" % (curdir, newdir)) + os.chdir(newdir) + + # Force a copy of the old path, instead of just a reference + old_path = list(sys.path) + old_modules = copy.copy(sys.modules) + sys.path.append(newdir) + + try: + yield + finally: + # Restore the old path + to_remove = [] + for module in sys.modules: + if module not in old_modules: + to_remove.append(module) + + for module in to_remove: + del(sys.modules[module]) + + sys.path = old_path + LOGGER.debug("Changing directory back from %s to %s" % (newdir, curdir)) + os.chdir(curdir) + + +def loadmod(name, path): + abspath = os.path.abspath(path) + loader = importlib.machinery.SourceFileLoader(name, abspath) + return loader.load_module() + + +# Get a big list of clean words for our answer file. +ANSWER_WORDS = [w.strip() for w in open(os.path.join(os.path.dirname(__file__), + 'answer_words.txt'))] + +class PuzzleFile: + """A file associated with a puzzle. + + path: The path to the original input file. May be None (when this is created from a file handle + and there is no original input. + handle: A File-like object set to read the file from. You should be able to read straight + from it without having to seek to the beginning of the file. + name: The name of the output file. + visible: A boolean indicating whether this file should visible to the user. If False, + the file is still expected to be accessible, but it's path must be known + (or figured out) to retrieve it.""" + + def __init__(self, stream, name, visible=True): + self.stream = stream + self.name = name + self.visible = visible + +class PuzzleSuccess(dict): + """Puzzle success objectives + + :param acceptable: Learning outcome from acceptable knowledge of the subject matter + :param mastery: Learning outcome from mastery of the subject matter + """ + + valid_fields = ["acceptable", "mastery"] + + def __init__(self, **kwargs): + super(PuzzleSuccess, self).__init__() + for key in self.valid_fields: + self[key] = None + for key, value in kwargs.items(): + if key in self.valid_fields: + self[key] = value + + def __getattr__(self, attr): + if attr in self.valid_fields: + return self[attr] + raise AttributeError("'%s' object has no attribute '%s'" % (type(self).__name__, attr)) + + def __setattr__(self, attr, value): + if attr in self.valid_fields: + self[attr] = value + else: + raise AttributeError("'%s' object has no attribute '%s'" % (type(self).__name__, attr)) + + +class Puzzle: + def __init__(self, category_seed, points): + """A MOTH Puzzle. + + :param category_seed: A byte string to use as a seed for random numbers for this puzzle. + It is combined with the puzzle points. + :param points: The point value of the puzzle. + """ + + super().__init__() + + self.points = points + self.summary = None + self.authors = [] + self.answers = [] + self.scripts = [] + self.pattern = None + self.hint = None + self.files = {} + self.body = io.StringIO() + + # NIST NICE objective content + self.objective = None # Text describing the expected learning outcome from solving this puzzle, *why* are you solving this puzzle + self.success = PuzzleSuccess() # Text describing criteria for different levels of success, e.g. {"Acceptable": "Did OK", "Mastery": "Did even better"} + self.solution = None # Text describing how to solve the puzzle + self.ksas = [] # A list of references to related NICE KSAs (e.g. K0058, . . .) + + self.logs = [] + self.randseed = category_seed * self.points + self.rand = random.Random(self.randseed) + + def log(self, *vals): + """Add a new log message to this puzzle.""" + msg = ' '.join(str(v) for v in vals) + self.logs.append(msg) + + def read_stream(self, stream): + header = True + line = "" + if stream.read(3) == "---": + header = "yaml" + else: + header = "moth" + + stream.seek(0) + + if header == "yaml": + LOGGER.info("Puzzle is YAML-formatted") + self.read_yaml_header(stream) + elif header == "moth": + LOGGER.info("Puzzle is MOTH-formatted") + self.read_moth_header(stream) + + for line in stream: + self.body.write(line) + + def read_yaml_header(self, stream): + contents = "" + header = False + for line in stream: + if line.strip() == "---" and header: # Handle last line + break + elif line.strip() == "---": # Handle first line + header = True + continue + else: + contents += line + + config = yaml.safe_load(contents) + for key, value in config.items(): + key = key.lower() + self.handle_header_key(key, value) + + def read_moth_header(self, stream): + for line in stream: + line = line.strip() + if not line: + break + + key, val = line.split(':', 1) + key = key.lower() + val = val.strip() + self.handle_header_key(key, val) + + def handle_header_key(self, key, val): + LOGGER.debug("Handling key: %s, value: %s", key, val) + if key == 'author': + self.authors.append(val) + elif key == 'authors': + if not isinstance(val, list): + raise ValueError("Authors must be a list, got %s, instead" & (type(val),)) + self.authors = list(val) + elif key == 'summary': + self.summary = val + elif key == 'answer': + if not isinstance(val, str): + raise ValueError("Answers must be strings, got %s, instead" % (type(val),)) + self.answers.append(val) + elif key == "answers": + for answer in val: + if not isinstance(answer, str): + raise ValueError("Answers must be strings, got %s, instead" % (type(answer),)) + self.answers.append(answer) + elif key == 'pattern': + self.pattern = val + elif key == 'hint': + self.hint = val + elif key == 'name': + pass + elif key == 'file': + parts = shlex.split(val) + name = parts[0] + hidden = False + LOGGER.debug("Attempting to open %s", os.path.abspath(name)) + stream = open(name, 'rb') + try: + name = parts[1] + hidden = (parts[2].lower() == "hidden") + except IndexError: + pass + self.files[name] = PuzzleFile(stream, name, not hidden) + elif key == 'script': + stream = open(val, 'rb') + # Make sure this shows up in the header block of the HTML output. + self.files[val] = PuzzleFile(stream, val, visible=False) + self.scripts.append(val) + elif key == "objective": + self.objective = val + elif key == "success": + # Force success dictionary keys to be lower-case + self.success = dict((x.lower(), y) for x,y in val.items()) + elif key == "success.acceptable": + self.success.acceptable = val + elif key == "success.mastery": + self.success.mastery = val + elif key == "solution": + self.solution = val + elif key == "ksas": + if not isinstance(val, list): + raise ValueError("KSAs must be a list, got %s, instead" & (type(val),)) + self.ksas = val + elif key == "ksa": + self.ksas.append(val) + else: + raise ValueError("Unrecognized header field: {}".format(key)) + + + def read_directory(self, path): + try: + puzzle_mod = loadmod("puzzle", os.path.join(path, "puzzle.py")) + except FileNotFoundError: + puzzle_mod = None + + with pushd(path): + if puzzle_mod: + puzzle_mod.make(self) + else: + with open('puzzle.moth') as f: + self.read_stream(f) + + def random_hash(self): + """Create a file basename (no extension) with our number generator.""" + return ''.join(self.rand.choice(string.ascii_lowercase) for i in range(8)) + + def make_temp_file(self, name=None, visible=True): + """Get a file object for adding dynamically generated data to the puzzle. When you're + done with this file, flush it, but don't close it. + + :param name: The name of the file for links within the puzzle. If this is None, a name + will be generated for you. + :param visible: Whether or not the file will be visible to the user. + :return: A file object for writing + """ + + stream = tempfile.TemporaryFile() + self.add_stream(stream, name, visible) + return stream + + def add_stream(self, stream, name=None, visible=True): + if name is None: + name = self.random_hash() + self.files[name] = PuzzleFile(stream, name, visible) + + def add_file(self, filename, visible=True): + fd = open(filename, 'rb') + name = os.path.basename(filename) + self.add_stream(fd, name=name, visible=visible) + + def randword(self): + """Return a randomly-chosen word""" + + return self.rand.choice(ANSWER_WORDS) + + def make_answer(self, word_count=4, sep=' '): + """Generate and return a new answer. It's automatically added to the puzzle answer list. + :param int word_count: The number of words to include in the answer. + :param str|bytes sep: The word separator. + :returns: The answer string + """ + + words = [self.randword() for i in range(word_count)] + answer = sep.join(words) + self.answers.append(answer) + return answer + + hexdump_stdch = stdch = ( + '················' + '················' + ' !"#$%&\'()*+,-./' + '0123456789:;<=>?' + '@ABCDEFGHIJKLMNO' + 'PQRSTUVWXYZ[\]^_' + '`abcdefghijklmno' + 'pqrstuvwxyz{|}~·' + '················' + '················' + '················' + '················' + '················' + '················' + '················' + '················' + ) + + def hexdump(self, buf, charset=hexdump_stdch, gap=('�', '⌷')): + hexes, chars = [], [] + out = [] + + for b in buf: + if len(chars) == 16: + out.append((hexes, chars)) + hexes, chars = [], [] + + if b is None: + h, c = gap + else: + h = '{:02x}'.format(b) + c = charset[b] + chars.append(c) + hexes.append(h) + + out.append((hexes, chars)) + + offset = 0 + elided = False + lastchars = None + self.body.write('
      ')
      +        for hexes, chars in out:
      +            if chars == lastchars:
      +                offset += len(chars)
      +                if not elided:
      +                    self.body.write('*\n')
      +                    elided = True
      +                continue
      +            lastchars = chars[:]
      +            elided = False
      +
      +            pad = 16 - len(chars)
      +            hexes += ['  '] * pad
      +
      +            self.body.write('{:08x}  '.format(offset))
      +            self.body.write(' '.join(hexes[:8]))
      +            self.body.write('  ')
      +            self.body.write(' '.join(hexes[8:]))
      +            self.body.write('  |')
      +            self.body.write(html.escape(''.join(chars)))
      +            self.body.write('|\n')
      +            offset += len(chars)
      +        self.body.write('{:08x}\n'.format(offset))
      +        self.body.write('
      ') + + def get_authors(self): + return self.authors or [self.author] + + def get_body(self): + return self.body.getvalue() + + def html_body(self): + """Format and return the markdown for the puzzle body.""" + return mistune.markdown(self.get_body(), escape=False) + + def package(self, answers=False): + """Return a dict packaging of the puzzle.""" + + files = [fn for fn,f in self.files.items() if f.visible] + return { + 'authors': self.get_authors(), + 'hashes': self.hashes(), + 'files': files, + 'scripts': self.scripts, + 'pattern': self.pattern, + 'body': self.html_body(), + 'objective': self.objective, + 'success': self.success, + 'solution': self.solution, + 'ksas': self.ksas, + } + + def hashes(self): + "Return a list of answer hashes" + + return [djb2hash(a) for a in self.answers] + + +class Category: + def __init__(self, path, seed): + self.path = path + self.seed = seed + self.catmod = None + + try: + self.catmod = loadmod('category', str(os.path.join(str(path), 'category.py'))) + except FileNotFoundError: + self.catmod = None + + def pointvals(self): + if self.catmod: + with pushd(self.path): + pointvals = self.catmod.pointvals() + else: + pointvals = [] + for fpath in glob.glob(str(os.path.join(str(self.path), "[0-9]*"))): + pn = os.path.basename(fpath) + points = int(pn) + pointvals.append(points) + return sorted(pointvals) + + def puzzle(self, points): + puzzle = Puzzle(self.seed, points) + path = str(os.path.join(str(self.path), str(points))) + if self.catmod: + with pushd(self.path): + self.catmod.make(points, puzzle) + else: + with pushd(str(self.path)): + puzzle.read_directory(path) + return puzzle + + def __iter__(self): + for points in self.pointvals(): + yield self.puzzle(points) diff --git a/contrib/python/setup.py b/contrib/python/setup.py new file mode 100644 index 0000000..4815396 --- /dev/null +++ b/contrib/python/setup.py @@ -0,0 +1,26 @@ +from setuptools import setup + +import sys +if sys.version_info < (3,5): + sys.exit("Sorry, Python < 3.5 is not supported") + +setup( + name = "moth", + version = open("VERSION", "r").read().strip(), + description = "The MOTH development toolkit", + packages = ["moth"], + python_requires = "~=3.5", + install_requires = [ + "mistune>=0.8.4", + "PyYAML>=5.3.1", + ], + extras_require = { + "scapy": ["scapy>=2.4.2"], + "pillow": ["Pillow>=5.4.1"], + "full": ["scapy>=2.5.2", "Pillow>=5.4.1"], + }, + include_package_data = True, + entry_points = { + "console_scripts": [], + }, +)