diff --git a/Student/stephen/lesson01/featuresdf.csv b/Student/stephen/lesson01/featuresdf.csv
new file mode 100644
index 0000000..ece51ea
--- /dev/null
+++ b/Student/stephen/lesson01/featuresdf.csv
@@ -0,0 +1,101 @@
+id,name,artists,danceability,energy,key,loudness,mode,speechiness,acousticness,instrumentalness,liveness,valence,tempo,duration_ms,time_signature
+7qiZfU4dY1lWllzX7mPBI,Shape of You,Ed Sheeran,0.825,0.652,1.0,-3.183,0.0,0.0802,0.581,0.0,0.0931,0.931,95.977,233713.0,4.0
+5CtI0qwDJkDQGwXD1H1cL,Despacito - Remix,Luis Fonsi,0.694,0.815,2.0,-4.328,1.0,0.12,0.229,0.0,0.0924,0.813,88.931,228827.0,4.0
+4aWmUDTfIPGksMNLV2rQP,Despacito (Featuring Daddy Yankee),Luis Fonsi,0.66,0.786,2.0,-4.757,1.0,0.17,0.209,0.0,0.112,0.846,177.833,228200.0,4.0
+6RUKPb4LETWmmr3iAEQkt,Something Just Like This,The Chainsmokers,0.617,0.635,11.0,-6.769,0.0,0.0317,0.0498,1.44e-05,0.164,0.446,103.019,247160.0,4.0
+3DXncPQOG4VBw3QHh3S81,I'm the One,DJ Khaled,0.609,0.668,7.0,-4.284,1.0,0.0367,0.0552,0.0,0.167,0.811,80.924,288600.0,4.0
+7KXjTSCq5nL1LoYtL7XAw,HUMBLE.,Kendrick Lamar,0.904,0.611,1.0,-6.842,0.0,0.0888,0.000259,2.03e-05,0.0976,0.4,150.02,177000.0,4.0
+3eR23VReFzcdmS7TYCrhC,It Ain't Me (with Selena Gomez),Kygo,0.64,0.533,0.0,-6.596,1.0,0.0706,0.119,0.0,0.0864,0.515,99.968,220781.0,4.0
+3B54sVLJ402zGa6Xm4YGN,Unforgettable,French Montana,0.726,0.769,6.0,-5.043,1.0,0.123,0.0293,0.0101,0.104,0.733,97.985,233902.0,4.0
+0KKkJNfGyhkQ5aFogxQAP,That's What I Like,Bruno Mars,0.853,0.56,1.0,-4.961,1.0,0.0406,0.013,0.0,0.0944,0.86,134.066,206693.0,4.0
+3NdDpSvN911VPGivFlV5d,"I Don’t Wanna Live Forever (Fifty Shades Darker) - From ""Fifty Shades Darker (Original Motion Picture Soundtrack)""",ZAYN,0.735,0.451,0.0,-8.374,1.0,0.0585,0.0631,1.3e-05,0.325,0.0862,117.973,245200.0,4.0
+7GX5flRQZVHRAGd6B4TmD,XO TOUR Llif3,Lil Uzi Vert,0.732,0.75,11.0,-6.366,0.0,0.231,0.00264,0.0,0.109,0.401,155.096,182707.0,4.0
+72jbDTw1piOOj770jWNea,Paris,The Chainsmokers,0.653,0.658,2.0,-6.428,1.0,0.0304,0.0215,1.66e-06,0.0939,0.219,99.99,221507.0,4.0
+0dA2Mk56wEzDgegdC6R17,Stay (with Alessia Cara),Zedd,0.679,0.634,5.0,-5.024,0.0,0.0654,0.232,0.0,0.115,0.498,102.013,210091.0,4.0
+4iLqG9SeJSnt0cSPICSjx,Attention,Charlie Puth,0.774,0.626,3.0,-4.432,0.0,0.0432,0.0969,3.12e-05,0.0848,0.777,100.041,211475.0,4.0
+0VgkVdmE4gld66l8iyGjg,Mask Off,Future,0.833,0.434,2.0,-8.795,1.0,0.431,0.0102,0.0219,0.165,0.281,150.062,204600.0,4.0
+3a1lNhkSLSkpJE4MSHpDu,Congratulations,Post Malone,0.627,0.812,6.0,-4.215,1.0,0.0358,0.198,0.0,0.212,0.504,123.071,220293.0,4.0
+6kex4EBAj0WHXDKZMEJaa,Swalla (feat. Nicki Minaj & Ty Dolla $ign),Jason Derulo,0.696,0.817,1.0,-3.862,1.0,0.109,0.075,0.0,0.187,0.782,98.064,216409.0,4.0
+6PCUP3dWmTjcTtXY02oFd,Castle on the Hill,Ed Sheeran,0.461,0.834,2.0,-4.868,1.0,0.0989,0.0232,1.14e-05,0.14,0.471,135.007,261154.0,4.0
+5knuzwU65gJK7IF5yJsua,Rockabye (feat. Sean Paul & Anne-Marie),Clean Bandit,0.72,0.763,9.0,-4.068,0.0,0.0523,0.406,0.0,0.18,0.742,101.965,251088.0,4.0
+0CcQNd8CINkwQfe1RDtGV,Believer,Imagine Dragons,0.779,0.787,10.0,-4.305,0.0,0.108,0.0524,0.0,0.14,0.708,124.982,204347.0,4.0
+2rb5MvYT7ZIxbKW5hfcHx,Mi Gente,J Balvin,0.543,0.677,11.0,-4.915,0.0,0.0993,0.0148,6.21e-06,0.13,0.294,103.809,189440.0,4.0
+0tKcYR2II1VCQWT79i5Nr,Thunder,Imagine Dragons,0.6,0.81,0.0,-4.749,1.0,0.0479,0.00683,0.21,0.155,0.298,167.88,187147.0,4.0
+5uCax9HTNlzGybIStD3vD,Say You Won't Let Go,James Arthur,0.358,0.557,10.0,-7.398,1.0,0.059,0.695,0.0,0.0902,0.494,85.043,211467.0,4.0
+79cuOz3SPQTuFrp8WgftA,There's Nothing Holdin' Me Back,Shawn Mendes,0.857,0.8,2.0,-4.035,1.0,0.0583,0.381,0.0,0.0913,0.966,121.996,199440.0,4.0
+6De0lHrwBfPfrhorm9q1X,Me Rehúso,Danny Ocean,0.744,0.804,1.0,-6.327,1.0,0.0677,0.0231,0.0,0.0494,0.426,104.823,205715.0,4.0
+6D0b04NJIKfEMg040WioJ,Issues,Julia Michaels,0.706,0.427,8.0,-6.864,1.0,0.0879,0.413,0.0,0.0609,0.42,113.804,176320.0,4.0
+0afhq8XCExXpqazXczTSv,Galway Girl,Ed Sheeran,0.624,0.876,9.0,-3.374,1.0,0.1,0.0735,0.0,0.327,0.781,99.943,170827.0,4.0
+3ebXMykcMXOcLeJ9xZ17X,Scared to Be Lonely,Martin Garrix,0.584,0.54,1.0,-7.786,0.0,0.0576,0.0895,0.0,0.261,0.195,137.972,220883.0,4.0
+7BKLCZ1jbUBVqRi2FVlTV,Closer,The Chainsmokers,0.748,0.524,8.0,-5.599,1.0,0.0338,0.414,0.0,0.111,0.661,95.01,244960.0,4.0
+1x5sYLZiu9r5E43kMlt9f,Symphony (feat. Zara Larsson),Clean Bandit,0.707,0.629,0.0,-4.581,0.0,0.0563,0.259,1.6e-05,0.138,0.457,122.863,212459.0,4.0
+5GXAXm5YOmYT0kL5jHvYB,I Feel It Coming,The Weeknd,0.768,0.813,0.0,-5.94,0.0,0.128,0.427,0.0,0.102,0.579,92.994,269187.0,4.0
+5aAx2yezTd8zXrkmtKl66,Starboy,The Weeknd,0.681,0.594,7.0,-7.028,1.0,0.282,0.165,3.49e-06,0.134,0.535,186.054,230453.0,4.0
+1OAh8uOEOvTDqkKFsKksC,Wild Thoughts,DJ Khaled,0.671,0.672,0.0,-3.094,0.0,0.0688,0.0329,0.0,0.118,0.632,97.98,204173.0,4.0
+7tr2za8SQg2CI8EDgrdtN,Slide,Calvin Harris,0.736,0.795,1.0,-3.299,0.0,0.0545,0.498,1.21e-06,0.254,0.511,104.066,230813.0,4.0
+2ekn2ttSfGqwhhate0LSR,New Rules,Dua Lipa,0.771,0.696,9.0,-6.258,0.0,0.0755,0.00256,9.71e-06,0.179,0.656,116.054,208827.0,4.0
+5tz69p7tJuGPeMGwNTxYu,1-800-273-8255,Logic,0.629,0.572,5.0,-7.733,0.0,0.0387,0.57,0.0,0.192,0.386,100.015,250173.0,4.0
+7hDc8b7IXETo14hHIHdnh,Passionfruit,Drake,0.809,0.463,11.0,-11.377,1.0,0.0396,0.256,0.085,0.109,0.364,111.98,298941.0,4.0
+7wGoVu4Dady5GV0Sv4UIs,rockstar,Post Malone,0.577,0.522,5.0,-6.594,0.0,0.0984,0.13,9.03e-05,0.142,0.119,159.772,218320.0,4.0
+6EpRaXYhGOB3fj4V2uDkM,Strip That Down,Liam Payne,0.869,0.485,6.0,-5.595,1.0,0.0545,0.246,0.0,0.0765,0.527,106.028,204502.0,4.0
+3A7qX2QjDlPnazUsRk5y0,2U (feat. Justin Bieber),David Guetta,0.548,0.65,8.0,-5.827,0.0,0.0591,0.219,0.0,0.225,0.557,144.937,194897.0,4.0
+0tgVpDi06FyKpA1z0VMD4,Perfect,Ed Sheeran,0.599,0.448,8.0,-6.312,1.0,0.0232,0.163,0.0,0.106,0.168,95.05,263400.0,3.0
+78rIJddV4X0HkNAInEcYd,Call On Me - Ryan Riback Extended Remix,Starley,0.676,0.843,0.0,-4.068,1.0,0.0367,0.0623,0.000752,0.181,0.718,105.003,222041.0,4.0
+5bcTCxgc7xVfSaMV3RuVk,Feels,Calvin Harris,0.893,0.745,11.0,-3.105,0.0,0.0571,0.0642,0.0,0.0943,0.872,101.018,223413.0,4.0
+0NiXXAI876aGImAd6rTj8,Mama,Jonas Blue,0.746,0.793,11.0,-4.209,0.0,0.0412,0.11,0.0,0.0528,0.557,104.027,181615.0,4.0
+0qYTZCo5Bwh1nsUFGZP3z,Felices los 4,Maluma,0.755,0.789,5.0,-4.502,1.0,0.146,0.231,0.0,0.351,0.737,93.973,229849.0,4.0
+2EEeOnHehOozLq4aS0n6S,iSpy (feat. Lil Yachty),KYLE,0.746,0.653,7.0,-6.745,1.0,0.289,0.378,0.0,0.229,0.672,75.016,253107.0,4.0
+152lZdxL1OR0ZMW6KquMi,Location,Khalid,0.736,0.449,1.0,-11.462,0.0,0.425,0.33,0.000162,0.0898,0.326,80.126,219080.0,4.0
+6mICuAdrwEjh6Y6lroV2K,Chantaje,Shakira,0.852,0.773,8.0,-2.921,0.0,0.0776,0.187,3.05e-05,0.159,0.907,102.034,195840.0,4.0
+4Km5HrUvYTaSUfiSGPJeQ,Bad and Boujee (feat. Lil Uzi Vert),Migos,0.927,0.665,11.0,-5.313,1.0,0.244,0.061,0.0,0.123,0.175,127.076,343150.0,4.0
+0ofbQMrRDsUaVKq2mGLEA,Havana,Camila Cabello,0.768,0.517,7.0,-4.323,0.0,0.0312,0.186,3.8e-05,0.104,0.418,104.992,216897.0,4.0
+6HUnnBwYZqcED1eQztxMB,Solo Dance,Martin Jensen,0.744,0.836,6.0,-2.396,0.0,0.0507,0.0435,0.0,0.194,0.36,114.965,174933.0,4.0
+343YBumqHu19cGoGARUTs,Fake Love,Drake,0.927,0.488,9.0,-9.433,0.0,0.42,0.108,0.0,0.196,0.605,133.987,210937.0,4.0
+4pdPtRcBmOSQDlJ3Fk945,Let Me Love You,DJ Snake,0.476,0.718,8.0,-5.309,1.0,0.0576,0.0784,1.02e-05,0.122,0.142,199.864,205947.0,4.0
+3PEgB3fkiojxms35ntsTg,More Than You Know,Axwell /\ Ingrosso,0.644,0.743,5.0,-5.002,0.0,0.0355,0.034,0.0,0.257,0.544,123.074,203000.0,4.0
+1xznGGDReH1oQq0xzbwXa,One Dance,Drake,0.791,0.619,1.0,-5.886,1.0,0.0532,0.00784,0.00423,0.351,0.371,103.989,173987.0,4.0
+7nKBxz47S9SD79N086fuh,SUBEME LA RADIO,Enrique Iglesias,0.684,0.823,9.0,-3.297,0.0,0.0773,0.0744,0.0,0.111,0.647,91.048,208163.0,4.0
+1NDxZ7cFAo481dtYWdrUn,Pretty Girl - Cheat Codes X CADE Remix,Maggie Lindemann,0.703,0.868,7.0,-4.661,0.0,0.0291,0.15,0.132,0.104,0.733,121.03,193613.0,4.0
+3m660poUr1chesgkkjQM7,Sorry Not Sorry,Demi Lovato,0.704,0.633,11.0,-6.923,0.0,0.241,0.0214,0.0,0.29,0.863,144.021,203760.0,4.0
+3kxfsdsCpFgN412fpnW85,Redbone,Childish Gambino,0.743,0.359,1.0,-10.401,1.0,0.0794,0.199,0.00611,0.137,0.587,160.083,326933.0,4.0
+6b8Be6ljOzmkOmFslEb23,24K Magic,Bruno Mars,0.818,0.803,1.0,-4.282,1.0,0.0797,0.034,0.0,0.153,0.632,106.97,225983.0,4.0
+6HZILIRieu8S0iqY8kIKh,DNA.,Kendrick Lamar,0.637,0.514,1.0,-6.763,1.0,0.365,0.0047,0.0,0.094,0.402,139.931,185947.0,4.0
+3umS4y3uQDkqekNjVpiRU,El Amante,Nicky Jam,0.683,0.691,8.0,-5.535,1.0,0.0432,0.243,0.0,0.14,0.732,179.91,219507.0,4.0
+00lNx0OcTJrS3MKHcB80H,You Don't Know Me - Radio Edit,Jax Jones,0.876,0.669,11.0,-6.054,0.0,0.138,0.163,0.0,0.185,0.682,124.007,213947.0,4.0
+6520aj0B4FSKGVuKNsOCO,Chained To The Rhythm,Katy Perry,0.448,0.801,0.0,-5.363,1.0,0.165,0.0733,0.0,0.146,0.462,189.798,237734.0,4.0
+1louJpMmzEicAn7lzDalP,No Promises (feat. Demi Lovato),Cheat Codes,0.741,0.667,10.0,-5.445,1.0,0.134,0.0575,0.0,0.106,0.595,112.956,223504.0,4.0
+2QbFClFyhMMtiurUjuQlA,Don't Wanna Know (feat. Kendrick Lamar),Maroon 5,0.775,0.617,7.0,-6.166,1.0,0.0701,0.341,0.0,0.0985,0.485,100.048,214265.0,4.0
+5hYTyyh2odQKphUbMqc5g,"How Far I'll Go - From ""Moana""",Alessia Cara,0.314,0.555,9.0,-9.601,1.0,0.37,0.157,0.000108,0.067,0.159,179.666,175517.0,4.0
+38yBBH2jacvDxrznF7h08,Slow Hands,Niall Horan,0.734,0.418,0.0,-6.678,1.0,0.0425,0.0129,0.0,0.0579,0.868,85.909,188174.0,4.0
+2cnKEkpVUSV4wnjQiTWfH,Escápate Conmigo,Wisin,0.747,0.864,8.0,-3.181,0.0,0.0599,0.0245,4.46e-05,0.0853,0.754,92.028,232787.0,4.0
+0SGkqnVQo9KPytSri1H6c,Bounce Back,Big Sean,0.77,0.567,2.0,-5.698,1.0,0.175,0.105,0.0,0.125,0.26,81.477,222360.0,4.0
+5Ohxk2dO5COHF1krpoPig,Sign of the Times,Harry Styles,0.516,0.595,5.0,-4.63,1.0,0.0313,0.0275,0.0,0.109,0.222,119.972,340707.0,4.0
+6gBFPUFcJLzWGx4lenP6h,goosebumps,Travis Scott,0.841,0.728,7.0,-3.37,1.0,0.0484,0.0847,0.0,0.149,0.43,130.049,243837.0,4.0
+5Z3GHaZ6ec9bsiI5Benrb,Young Dumb & Broke,Khalid,0.798,0.539,1.0,-6.351,1.0,0.0421,0.199,1.66e-05,0.165,0.394,136.949,202547.0,4.0
+6jA8HL9i4QGzsj6fjoxp8,There for You,Martin Garrix,0.611,0.644,6.0,-7.607,0.0,0.0553,0.124,0.0,0.124,0.13,105.969,221904.0,4.0
+21TdkDRXuAB3k90ujRU1e,Cold (feat. Future),Maroon 5,0.697,0.716,9.0,-6.288,0.0,0.113,0.118,0.0,0.0424,0.506,99.905,234308.0,4.0
+7vGuf3Y35N4wmASOKLUVV,Silence,Marshmello,0.52,0.761,4.0,-3.093,1.0,0.0853,0.256,4.96e-06,0.17,0.286,141.971,180823.0,4.0
+1mXVgsBdtIVeCLJnSnmtd,Too Good At Goodbyes,Sam Smith,0.698,0.375,5.0,-8.279,1.0,0.0491,0.652,0.0,0.173,0.534,91.92,201000.0,4.0
+3EmmCZoqpWOTY1g2GBwJo,Just Hold On,Steve Aoki,0.647,0.932,11.0,-3.515,1.0,0.0824,0.00383,1.5e-06,0.0574,0.374,114.991,198774.0,4.0
+6uFsE1JgZ20EXyU0JQZbU,Look What You Made Me Do,Taylor Swift,0.773,0.68,9.0,-6.378,0.0,0.141,0.213,1.57e-05,0.122,0.497,128.062,211859.0,4.0
+0CokSRCu5hZgPxcZBaEzV,Glorious (feat. Skylar Grey),Macklemore,0.731,0.794,0.0,-5.126,0.0,0.0522,0.0323,2.59e-05,0.112,0.356,139.994,220454.0,4.0
+6875MeXyCW0wLyT72Eetm,Starving,Hailee Steinfeld,0.721,0.626,4.0,-4.2,1.0,0.123,0.402,0.0,0.102,0.558,99.914,181933.0,4.0
+3AEZUABDXNtecAOSC1qTf,Reggaetón Lento (Bailemos),CNCO,0.761,0.838,4.0,-3.073,0.0,0.0502,0.4,0.0,0.176,0.71,93.974,222560.0,4.0
+3E2Zh20GDCR9B1EYjfXWy,Weak,AJR,0.673,0.637,5.0,-4.518,1.0,0.0429,0.137,0.0,0.184,0.678,123.98,201160.0,4.0
+4pLwZjInHj3SimIyN9SnO,Side To Side,Ariana Grande,0.648,0.738,6.0,-5.883,0.0,0.247,0.0408,0.0,0.292,0.603,159.145,226160.0,4.0
+3QwBODjSEzelZyVjxPOHd,Otra Vez (feat. J Balvin),Zion & Lennox,0.832,0.772,10.0,-5.429,1.0,0.1,0.0559,0.000486,0.44,0.704,96.016,209453.0,4.0
+1wjzFQodRWrPcQ0AnYnvQ,I Like Me Better,Lauv,0.752,0.505,9.0,-7.621,1.0,0.253,0.535,2.55e-06,0.104,0.419,91.97,197437.0,4.0
+04DwTuZ2VBdJCCC5TROn7,In the Name of Love,Martin Garrix,0.49,0.485,4.0,-6.237,0.0,0.0406,0.0592,0.0,0.337,0.196,133.889,195840.0,4.0
+6DNtNfH8hXkqOX1sjqmI7,Cold Water (feat. Justin Bieber & MØ),Major Lazer,0.608,0.798,6.0,-5.092,0.0,0.0432,0.0736,0.0,0.156,0.501,92.943,185352.0,4.0
+1UZOjK1BwmwWU14Erba9C,Malibu,Miley Cyrus,0.573,0.781,8.0,-6.406,1.0,0.0555,0.0767,2.64e-05,0.0813,0.343,139.934,231907.0,4.0
+4b4KcovePX8Ke2cLIQTLM,All Night,The Vamps,0.544,0.809,8.0,-5.098,1.0,0.0363,0.0038,0.0,0.323,0.448,145.017,197640.0,4.0
+1a5Yu5L18qNxVhXx38njO,Hear Me Now,Alok,0.789,0.442,11.0,-7.844,1.0,0.0421,0.586,0.00366,0.0927,0.45,121.971,192846.0,4.0
+4c2W3VKsOFoIg2SFaO6DY,Your Song,Rita Ora,0.855,0.624,1.0,-4.093,1.0,0.0488,0.158,0.0,0.0513,0.962,117.959,180757.0,4.0
+22eADXu8DfOAUEDw4vU8q,Ahora Dice,Chris Jeday,0.708,0.693,6.0,-5.516,1.0,0.138,0.246,0.0,0.129,0.427,143.965,271080.0,4.0
+7nZmah2llfvLDiUjm0kiy,Friends (with BloodPop®),Justin Bieber,0.744,0.739,8.0,-5.35,1.0,0.0387,0.00459,0.0,0.306,0.649,104.99,189467.0,4.0
+2fQrGHiQOvpL9UgPvtYy6,Bank Account,21 Savage,0.884,0.346,8.0,-8.228,0.0,0.351,0.0151,7.04e-06,0.0871,0.376,75.016,220307.0,4.0
+1PSBzsahR2AKwLJgx8ehB,Bad Things (with Camila Cabello),Machine Gun Kelly,0.675,0.69,2.0,-4.761,1.0,0.132,0.21,0.0,0.287,0.272,137.817,239293.0,4.0
+0QsvXIfqM0zZoerQfsI9l,Don't Let Me Down,The Chainsmokers,0.542,0.859,11.0,-5.651,1.0,0.197,0.16,0.00466,0.137,0.403,159.797,208053.0,4.0
+7mldq42yDuxiUNn08nvzH,Body Like A Back Road,Sam Hunt,0.731,0.469,5.0,-7.226,1.0,0.0326,0.463,1.04e-06,0.103,0.631,98.963,165387.0,4.0
+7i2DJ88J7jQ8K7zqFX2fW,Now Or Never,Halsey,0.658,0.588,6.0,-4.902,0.0,0.0367,0.105,1.28e-06,0.125,0.434,110.075,214802.0,4.0
+1j4kHkkpqZRBwE0A4CN4Y,Dusk Till Dawn - Radio Edit,ZAYN,0.258,0.437,11.0,-6.593,0.0,0.039,0.101,1.27e-06,0.106,0.0967,180.043,239000.0,4.0
diff --git a/Student/stephen/lesson01/generator_solution.py b/Student/stephen/lesson01/generator_solution.py
new file mode 100644
index 0000000..585d7a6
--- /dev/null
+++ b/Student/stephen/lesson01/generator_solution.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+
+"""
+Build Generators:
+Sum of integers
+Doubler
+Fibonacci sequence
+Prime numbers
+"""
+
+def intsum(i=0):
+ n = 0
+ while True:
+ yield i
+ n += 1
+ i += n
+
+def intsum2(i=0):
+ n = 0
+ while True:
+ yield i
+ n += 1
+ i += n
+
+def doubler(i=1):
+ while True:
+ yield i
+ i *= 2
+
+def fib(i=0):
+ j = 1
+ while True:
+ yield j
+ h = i
+ i = j
+ j = h + i
+
+def prime(i=2):
+ while True:
+ if i == 2 or 0 not in [i % x for x in range(2, i)]:
+ yield i
+ i += 1
+
+def squared(i=0):
+ while True:
+ yield i ** 2
+ i += 1
+
+def cubed(i=0):
+ while True:
+ yield i ** 3
+ i += 1
+
+def threes(i=3):
+ while True:
+ yield i
+ i += 3
+
+
+from math import e
+
+def exp(i=0):
+ while True:
+ yield i ** e
+ i += 1
+
+def negseven(i=0):
+ while True:
+ yield i
+ i += -7
+
diff --git a/Student/stephen/lesson01/iterator_1.py b/Student/stephen/lesson01/iterator_1.py
new file mode 100644
index 0000000..c4aeccc
--- /dev/null
+++ b/Student/stephen/lesson01/iterator_1.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+"""
+Simple iterator examples
+"""
+
+
+class IterateMe_1:
+ """
+ About as simple an iterator as you can get:
+
+ returns the sequence of numbers from zero to 4
+ ( like range(4) )
+ """
+
+ def __init__(self, start, stop, step=1):
+ self.current = start - step
+ self.start = start
+ self.stop = stop
+ self.step = step
+
+
+ # iterator version
+ # def __iter__(self):
+ # return self
+
+ # mimic range iterable
+ def __iter__(self):
+ self.current = self.start - self.step
+ return self
+
+ def __next__(self):
+ self.current += self.step
+ if self.current < self.stop:
+ return self.current
+ else:
+ raise StopIteration
+
+
+
+if __name__ == "__main__":
+
+ print("Testing the iterator")
+ it = IterateMe_1(0, 20, 1)
+ for i in it:
+ if i > 10: break
+ print(i)
+ for i in it:
+ print(i)
+
+ print("Testing range")
+ rg = range(0, 20, 1)
+ for i in rg:
+ if i > 10: break
+ print(i)
+ for i in rg:
+ print(i)
+
+ print("Range objects are iterable; they do not keep track of state")
+
diff --git a/Student/stephen/lesson01/lesson01_assignment_comprehensions.ipynb b/Student/stephen/lesson01/lesson01_assignment_comprehensions.ipynb
new file mode 100644
index 0000000..5f02252
--- /dev/null
+++ b/Student/stephen/lesson01/lesson01_assignment_comprehensions.ipynb
@@ -0,0 +1,609 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "import pandas as pd"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "music = pd.read_csv(\"featuresdf.csv\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " id \n",
+ " name \n",
+ " artists \n",
+ " danceability \n",
+ " energy \n",
+ " key \n",
+ " loudness \n",
+ " mode \n",
+ " speechiness \n",
+ " acousticness \n",
+ " instrumentalness \n",
+ " liveness \n",
+ " valence \n",
+ " tempo \n",
+ " duration_ms \n",
+ " time_signature \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 7qiZfU4dY1lWllzX7mPBI \n",
+ " Shape of You \n",
+ " Ed Sheeran \n",
+ " 0.825 \n",
+ " 0.652 \n",
+ " 1.0 \n",
+ " -3.183 \n",
+ " 0.0 \n",
+ " 0.0802 \n",
+ " 0.5810 \n",
+ " 0.000000 \n",
+ " 0.0931 \n",
+ " 0.931 \n",
+ " 95.977 \n",
+ " 233713.0 \n",
+ " 4.0 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 5CtI0qwDJkDQGwXD1H1cL \n",
+ " Despacito - Remix \n",
+ " Luis Fonsi \n",
+ " 0.694 \n",
+ " 0.815 \n",
+ " 2.0 \n",
+ " -4.328 \n",
+ " 1.0 \n",
+ " 0.1200 \n",
+ " 0.2290 \n",
+ " 0.000000 \n",
+ " 0.0924 \n",
+ " 0.813 \n",
+ " 88.931 \n",
+ " 228827.0 \n",
+ " 4.0 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " 4aWmUDTfIPGksMNLV2rQP \n",
+ " Despacito (Featuring Daddy Yankee) \n",
+ " Luis Fonsi \n",
+ " 0.660 \n",
+ " 0.786 \n",
+ " 2.0 \n",
+ " -4.757 \n",
+ " 1.0 \n",
+ " 0.1700 \n",
+ " 0.2090 \n",
+ " 0.000000 \n",
+ " 0.1120 \n",
+ " 0.846 \n",
+ " 177.833 \n",
+ " 228200.0 \n",
+ " 4.0 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " 6RUKPb4LETWmmr3iAEQkt \n",
+ " Something Just Like This \n",
+ " The Chainsmokers \n",
+ " 0.617 \n",
+ " 0.635 \n",
+ " 11.0 \n",
+ " -6.769 \n",
+ " 0.0 \n",
+ " 0.0317 \n",
+ " 0.0498 \n",
+ " 0.000014 \n",
+ " 0.1640 \n",
+ " 0.446 \n",
+ " 103.019 \n",
+ " 247160.0 \n",
+ " 4.0 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 3DXncPQOG4VBw3QHh3S81 \n",
+ " I'm the One \n",
+ " DJ Khaled \n",
+ " 0.609 \n",
+ " 0.668 \n",
+ " 7.0 \n",
+ " -4.284 \n",
+ " 1.0 \n",
+ " 0.0367 \n",
+ " 0.0552 \n",
+ " 0.000000 \n",
+ " 0.1670 \n",
+ " 0.811 \n",
+ " 80.924 \n",
+ " 288600.0 \n",
+ " 4.0 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " id name \\\n",
+ "0 7qiZfU4dY1lWllzX7mPBI Shape of You \n",
+ "1 5CtI0qwDJkDQGwXD1H1cL Despacito - Remix \n",
+ "2 4aWmUDTfIPGksMNLV2rQP Despacito (Featuring Daddy Yankee) \n",
+ "3 6RUKPb4LETWmmr3iAEQkt Something Just Like This \n",
+ "4 3DXncPQOG4VBw3QHh3S81 I'm the One \n",
+ "\n",
+ " artists danceability energy key loudness mode speechiness \\\n",
+ "0 Ed Sheeran 0.825 0.652 1.0 -3.183 0.0 0.0802 \n",
+ "1 Luis Fonsi 0.694 0.815 2.0 -4.328 1.0 0.1200 \n",
+ "2 Luis Fonsi 0.660 0.786 2.0 -4.757 1.0 0.1700 \n",
+ "3 The Chainsmokers 0.617 0.635 11.0 -6.769 0.0 0.0317 \n",
+ "4 DJ Khaled 0.609 0.668 7.0 -4.284 1.0 0.0367 \n",
+ "\n",
+ " acousticness instrumentalness liveness valence tempo duration_ms \\\n",
+ "0 0.5810 0.000000 0.0931 0.931 95.977 233713.0 \n",
+ "1 0.2290 0.000000 0.0924 0.813 88.931 228827.0 \n",
+ "2 0.2090 0.000000 0.1120 0.846 177.833 228200.0 \n",
+ "3 0.0498 0.000014 0.1640 0.446 103.019 247160.0 \n",
+ "4 0.0552 0.000000 0.1670 0.811 80.924 288600.0 \n",
+ "\n",
+ " time_signature \n",
+ "0 4.0 \n",
+ "1 4.0 \n",
+ "2 4.0 \n",
+ "3 4.0 \n",
+ "4 4.0 "
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "music.head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " danceability \n",
+ " energy \n",
+ " key \n",
+ " loudness \n",
+ " mode \n",
+ " speechiness \n",
+ " acousticness \n",
+ " instrumentalness \n",
+ " liveness \n",
+ " valence \n",
+ " tempo \n",
+ " duration_ms \n",
+ " time_signature \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 100.00000 \n",
+ " 100.000000 \n",
+ " 100.000000 \n",
+ " 100.000000 \n",
+ " 100.000000 \n",
+ " 100.000000 \n",
+ " 100.000000 \n",
+ " 100.000000 \n",
+ " 100.000000 \n",
+ " 100.000000 \n",
+ " 100.000000 \n",
+ " 100.00000 \n",
+ " 100.00 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " 0.69682 \n",
+ " 0.660690 \n",
+ " 5.570000 \n",
+ " -5.652650 \n",
+ " 0.580000 \n",
+ " 0.103969 \n",
+ " 0.166306 \n",
+ " 0.004796 \n",
+ " 0.150607 \n",
+ " 0.517049 \n",
+ " 119.202460 \n",
+ " 218387.28000 \n",
+ " 3.99 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 0.12508 \n",
+ " 0.139207 \n",
+ " 3.731534 \n",
+ " 1.802067 \n",
+ " 0.496045 \n",
+ " 0.095115 \n",
+ " 0.166730 \n",
+ " 0.026038 \n",
+ " 0.079011 \n",
+ " 0.216436 \n",
+ " 27.952928 \n",
+ " 32851.07772 \n",
+ " 0.10 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " 0.25800 \n",
+ " 0.346000 \n",
+ " 0.000000 \n",
+ " -11.462000 \n",
+ " 0.000000 \n",
+ " 0.023200 \n",
+ " 0.000259 \n",
+ " 0.000000 \n",
+ " 0.042400 \n",
+ " 0.086200 \n",
+ " 75.016000 \n",
+ " 165387.00000 \n",
+ " 3.00 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " 0.63500 \n",
+ " 0.556500 \n",
+ " 2.000000 \n",
+ " -6.594500 \n",
+ " 0.000000 \n",
+ " 0.043125 \n",
+ " 0.039100 \n",
+ " 0.000000 \n",
+ " 0.098275 \n",
+ " 0.375500 \n",
+ " 99.911750 \n",
+ " 198490.50000 \n",
+ " 4.00 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " 0.71400 \n",
+ " 0.667500 \n",
+ " 6.000000 \n",
+ " -5.437000 \n",
+ " 1.000000 \n",
+ " 0.062650 \n",
+ " 0.106500 \n",
+ " 0.000000 \n",
+ " 0.125000 \n",
+ " 0.502500 \n",
+ " 112.468000 \n",
+ " 214106.00000 \n",
+ " 4.00 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " 0.77025 \n",
+ " 0.787500 \n",
+ " 9.000000 \n",
+ " -4.326750 \n",
+ " 1.000000 \n",
+ " 0.123000 \n",
+ " 0.231250 \n",
+ " 0.000013 \n",
+ " 0.179250 \n",
+ " 0.679000 \n",
+ " 137.166000 \n",
+ " 230543.00000 \n",
+ " 4.00 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " 0.92700 \n",
+ " 0.932000 \n",
+ " 11.000000 \n",
+ " -2.396000 \n",
+ " 1.000000 \n",
+ " 0.431000 \n",
+ " 0.695000 \n",
+ " 0.210000 \n",
+ " 0.440000 \n",
+ " 0.966000 \n",
+ " 199.864000 \n",
+ " 343150.00000 \n",
+ " 4.00 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " danceability energy key loudness mode \\\n",
+ "count 100.00000 100.000000 100.000000 100.000000 100.000000 \n",
+ "mean 0.69682 0.660690 5.570000 -5.652650 0.580000 \n",
+ "std 0.12508 0.139207 3.731534 1.802067 0.496045 \n",
+ "min 0.25800 0.346000 0.000000 -11.462000 0.000000 \n",
+ "25% 0.63500 0.556500 2.000000 -6.594500 0.000000 \n",
+ "50% 0.71400 0.667500 6.000000 -5.437000 1.000000 \n",
+ "75% 0.77025 0.787500 9.000000 -4.326750 1.000000 \n",
+ "max 0.92700 0.932000 11.000000 -2.396000 1.000000 \n",
+ "\n",
+ " speechiness acousticness instrumentalness liveness valence \\\n",
+ "count 100.000000 100.000000 100.000000 100.000000 100.000000 \n",
+ "mean 0.103969 0.166306 0.004796 0.150607 0.517049 \n",
+ "std 0.095115 0.166730 0.026038 0.079011 0.216436 \n",
+ "min 0.023200 0.000259 0.000000 0.042400 0.086200 \n",
+ "25% 0.043125 0.039100 0.000000 0.098275 0.375500 \n",
+ "50% 0.062650 0.106500 0.000000 0.125000 0.502500 \n",
+ "75% 0.123000 0.231250 0.000013 0.179250 0.679000 \n",
+ "max 0.431000 0.695000 0.210000 0.440000 0.966000 \n",
+ "\n",
+ " tempo duration_ms time_signature \n",
+ "count 100.000000 100.00000 100.00 \n",
+ "mean 119.202460 218387.28000 3.99 \n",
+ "std 27.952928 32851.07772 0.10 \n",
+ "min 75.016000 165387.00000 3.00 \n",
+ "25% 99.911750 198490.50000 4.00 \n",
+ "50% 112.468000 214106.00000 4.00 \n",
+ "75% 137.166000 230543.00000 4.00 \n",
+ "max 199.864000 343150.00000 4.00 "
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "music.describe()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[0.825,\n",
+ " 0.904,\n",
+ " 0.853,\n",
+ " 0.833,\n",
+ " 0.857,\n",
+ " 0.809,\n",
+ " 0.8690000000000001,\n",
+ " 0.893,\n",
+ " 0.852,\n",
+ " 0.927,\n",
+ " 0.927,\n",
+ " 0.818,\n",
+ " 0.8759999999999999,\n",
+ " 0.841,\n",
+ " 0.8320000000000001,\n",
+ " 0.855,\n",
+ " 0.884]"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "[x for x in music.danceability if x > 0.8]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Your job, now, is to get artists and song names for tracks with danceability scores over 0.8 and loudness scores below -5.0.\n",
+ "#### Also, these tracks should be sorted in descending order by danceability so that the most danceable tracks are up top."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# zip the artists, songs, danceability and loudness\n",
+ "songlist = zip(music.name, music.artists, music.danceability, music.loudness)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "filteredsongs = [(name, artists, danceability, loudness) for name, artists, danceability, loudness in songlist if danceability > 0.8 and loudness < -5.0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "topfive = pd.DataFrame(sorted(filteredsongs, key=(lambda x: x[2]), reverse=True), columns=['name', 'artists', 'danceability', 'loudness'])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " name \n",
+ " artists \n",
+ " danceability \n",
+ " loudness \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " Bad and Boujee (feat. Lil Uzi Vert) \n",
+ " Migos \n",
+ " 0.927 \n",
+ " -5.313 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " Fake Love \n",
+ " Drake \n",
+ " 0.927 \n",
+ " -9.433 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " HUMBLE. \n",
+ " Kendrick Lamar \n",
+ " 0.904 \n",
+ " -6.842 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " Bank Account \n",
+ " 21 Savage \n",
+ " 0.884 \n",
+ " -8.228 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " You Don't Know Me - Radio Edit \n",
+ " Jax Jones \n",
+ " 0.876 \n",
+ " -6.054 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " name artists danceability loudness\n",
+ "0 Bad and Boujee (feat. Lil Uzi Vert) Migos 0.927 -5.313\n",
+ "1 Fake Love Drake 0.927 -9.433\n",
+ "2 HUMBLE. Kendrick Lamar 0.904 -6.842\n",
+ "3 Bank Account 21 Savage 0.884 -8.228\n",
+ "4 You Don't Know Me - Radio Edit Jax Jones 0.876 -6.054"
+ ]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "topfive.head(5)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/Student/stephen/lesson01/lesson01_assignment_comprehensions.py b/Student/stephen/lesson01/lesson01_assignment_comprehensions.py
new file mode 100644
index 0000000..64b281f
--- /dev/null
+++ b/Student/stephen/lesson01/lesson01_assignment_comprehensions.py
@@ -0,0 +1,62 @@
+
+# coding: utf-8
+
+# In[2]:
+
+
+import pandas as pd
+
+
+# In[3]:
+
+
+music = pd.read_csv("featuresdf.csv")
+
+
+# In[4]:
+
+
+music.head()
+
+
+# In[5]:
+
+
+music.describe()
+
+
+# In[6]:
+
+
+[x for x in music.danceability if x > 0.8]
+
+
+# #### Your job, now, is to get artists and song names for tracks with danceability scores over 0.8 and loudness scores below -5.0.
+# #### Also, these tracks should be sorted in descending order by danceability so that the most danceable tracks are up top.
+
+# In[28]:
+
+
+# zip the artists, songs, danceability and loudness
+songlist = zip(music.name, music.artists, music.danceability, music.loudness)
+
+
+# In[29]:
+
+
+filteredsongs = [(name, artists, danceability, loudness) for name, artists, danceability, loudness in songlist if danceability > 0.8 and loudness < -5.0]
+
+
+# In[42]:
+
+
+topfive = pd.DataFrame(sorted(filteredsongs, key=(lambda x: x[2]), reverse=True), columns=['name', 'artists', 'danceability', 'loudness'])
+
+
+# In[45]:
+topfive.head(5)
+
+if __name__ == '__main__':
+ print(topfive.head(5))
+
+
diff --git a/Student/stephen/lesson01/test_generator.py b/Student/stephen/lesson01/test_generator.py
new file mode 100644
index 0000000..4bf5e72
--- /dev/null
+++ b/Student/stephen/lesson01/test_generator.py
@@ -0,0 +1,89 @@
+"""
+test_generator.py
+
+tests the solution to the generator lab
+
+can be run with py.test or nosetests
+"""
+
+import generator_solution as gen
+from math import e
+
+
+def test_intsum():
+
+ g = gen.intsum()
+
+ assert next(g) == 0
+ assert next(g) == 1
+ assert next(g) == 3
+ assert next(g) == 6
+ assert next(g) == 10
+ assert next(g) == 15
+
+
+def test_intsum2():
+
+ g = gen.intsum2()
+
+ assert next(g) == 0
+ assert next(g) == 1
+ assert next(g) == 3
+ assert next(g) == 6
+ assert next(g) == 10
+ assert next(g) == 15
+
+
+def test_doubler():
+
+ g = gen.doubler()
+
+ assert next(g) == 1
+ assert next(g) == 2
+ assert next(g) == 4
+ assert next(g) == 8
+ assert next(g) == 16
+ assert next(g) == 32
+
+ for j in range(10):
+ j = next(g)
+
+ assert j == 2**15
+
+
+def test_fib():
+ g = gen.fib()
+ assert [next(g) for i in range(9)] == [1, 1, 2, 3, 5, 8, 13, 21, 34]
+
+
+def test_prime():
+ g = gen.prime()
+ for val in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]:
+ assert next(g) == val
+
+def test_squared():
+ g = gen.squared()
+ for val in [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144]:
+ assert next(g) == val
+
+
+def test_cubed():
+ g = gen.cubed()
+ for val in [0, 1, 8, 27, 64, 125, 216]:
+ assert next(g) == val
+
+def test_threes():
+ g = gen.threes()
+ for val in [3, 6, 9, 12, 15, 18, 21]:
+ assert next(g) == val
+
+
+def test_exp():
+ g = gen.exp()
+ for val in [0 ** e, 1 ** e, 2 ** e, 3 ** e, 4 ** e, 5 ** e, 6 ** e]:
+ assert next(g) == val
+
+def test_negseven():
+ g = gen.negseven()
+ for val in [0, -7, -14, -21, -28, -35, -42]:
+ assert next(g) == val
diff --git a/Student/stephen/lesson02/In-Class_Activity.ipynb b/Student/stephen/lesson02/In-Class_Activity.ipynb
new file mode 100644
index 0000000..56ef276
--- /dev/null
+++ b/Student/stephen/lesson02/In-Class_Activity.ipynb
@@ -0,0 +1,476 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Iterators"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def check_prime(number):\n",
+ " for divisor in range(2, int(number ** 0.5) + 1):\n",
+ " if number % divisor == 0:\n",
+ " return False\n",
+ " return True"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ " class Primes:\n",
+ " def __init__(self, max):\n",
+ " self.max = max\n",
+ " self.number = 1\n",
+ " def __iter__(self):\n",
+ " return self\n",
+ " def __next__(self):\n",
+ " self.number += 1\n",
+ " if self.number >= self.max:\n",
+ " raise StopIteration\n",
+ " elif check_prime(self.number):\n",
+ " return self.number\n",
+ " else:\n",
+ " return self.__next__()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "<__main__.Primes object at 0x00000277B24BA748>\n",
+ "2\n",
+ "3\n",
+ "5\n",
+ "7\n"
+ ]
+ }
+ ],
+ "source": [
+ "primes = Primes(10)\n",
+ "print(primes)\n",
+ "for x in primes:\n",
+ " print(x) "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Generators\n",
+ "\n",
+ "A generator must have a yield\n",
+ "It can yield many number of times\n",
+ "Yield is two way - you can input and output\n",
+ "It saves state\n",
+ "It is a better version than Iterator or regular function"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "2\n",
+ "3\n",
+ "5\n",
+ "7\n",
+ "11\n",
+ "13\n",
+ "17\n",
+ "19\n",
+ "23\n",
+ "29\n",
+ "31\n",
+ "37\n",
+ "41\n",
+ "43\n",
+ "47\n",
+ "53\n",
+ "59\n",
+ "61\n",
+ "67\n",
+ "71\n",
+ "73\n",
+ "79\n",
+ "83\n",
+ "89\n",
+ "97\n"
+ ]
+ }
+ ],
+ "source": [
+ "def Primes(max):\n",
+ " number = 1\n",
+ " while number < max:\n",
+ " number += 1\n",
+ " if check_prime(number):\n",
+ " yield number\n",
+ "primes = Primes(100)\n",
+ "print(primes)\n",
+ "for x in primes:\n",
+ " print(x)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "A typical list looks like this:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "variable = [out_exp for out_exp in input_list if out_exp == 2]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Generator Expression\n",
+ "This takes advantage of \"lazy evaluation\"\n",
+ "Only the current value is loaded into memory"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "285"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sum([x*x for x in range(10)])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Closures"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Closures are a type of nested function\n",
+ "Recursive functions are a type of nested function\n",
+ "Higher order functions\n",
+ "\n",
+ "Closures: when you have a function inside a function and have a local variable in that function\n",
+ "The function protects the scope of that function\n",
+ "Closures must be inside a function and it must return a function"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Closure Example -"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hey!\n"
+ ]
+ }
+ ],
+ "source": [
+ " def outerFunction(text):\n",
+ " text = text\n",
+ " \n",
+ " def innerFunction():\n",
+ " print(text)\n",
+ " \n",
+ " return innerFunction # Note we are returning function WITHOUT parenthesis\n",
+ " \n",
+ "if __name__ == '__main__':\n",
+ " myFunction = outerFunction('Hey!')\n",
+ " myFunction()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Nonlocal variables are neither local or global variables\n",
+ "There are times when you don't use non local, it might still reflect that state outside .... for example...\n",
+ "Dictionary insertion is not an assignment, but a method call.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Nonlocal versus Global:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'outside': 1, 'inside': 2}\n",
+ "{'outside': 1, 'inside': 2}\n"
+ ]
+ }
+ ],
+ "source": [
+ " def outside():\n",
+ " d = {\"outside\": 1}\n",
+ " def inside():\n",
+ " #nonlocal d\n",
+ " d[\"inside\"] = 2\n",
+ " print(d)\n",
+ " inside()\n",
+ " print(d)\n",
+ " \n",
+ "outside()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'inside': 2}\n",
+ "Outside\n",
+ "{'outside': 1}\n"
+ ]
+ }
+ ],
+ "source": [
+ "def outside():\n",
+ " d = {\"outside\": 1}\n",
+ " def inside():\n",
+ " # nonlocal d\n",
+ " d = {\"inside\":2}\n",
+ " print(d)\n",
+ " inside()\n",
+ " print(\"Outside\")\n",
+ " print(d)\n",
+ " \n",
+ "outside()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "import heapq"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[1, 2, 4, 6]"
+ ]
+ },
+ "execution_count": 33,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# without partial\n",
+ "heap =[]\n",
+ "heapq.heappush(heap,1)\n",
+ "heapq.heappush(heap,2)\n",
+ "heapq.heappush(heap,4)\n",
+ "heapq.heappush(heap,6)\n",
+ "heapq.heappush(heap,7)\n",
+ "heapq.heappush(heap,9)\n",
+ "heapq.heappush(heap,10)\n",
+ "heapq.heappush(heap,12) \n",
+ "heapq.nsmallest(4, heap)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "import functools"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[1, 3, 4, 5, 6, 8]"
+ ]
+ },
+ "execution_count": 32,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import functools\n",
+ "import heapq\n",
+ "heap =[]\n",
+ "push = functools.partial(heapq.heappush, heap)\n",
+ "smallest = functools.partial(heapq.nsmallest, iterable=heap)\n",
+ "push(1)\n",
+ "push(3)\n",
+ "push(5)\n",
+ "push(6)\n",
+ "push(8)\n",
+ "push(11)\n",
+ "push(4)\n",
+ "push(16)\n",
+ "push(17)\n",
+ "smallest(6)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# from itertools import *\n",
+ "# for i in itertools.zip([1,2,3], ['a', 'b', 'c']):\n",
+ "# print(i)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import itertools\n",
+ "example = itertools.islice('ABSDEFG' , 2, None)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "S\n",
+ "D\n",
+ "E\n",
+ "F\n",
+ "G\n"
+ ]
+ }
+ ],
+ "source": [
+ "for x in example:\n",
+ " print(x)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "S D E F G\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(*example)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/Student/stephen/lesson02/featuresdf.csv b/Student/stephen/lesson02/featuresdf.csv
new file mode 100644
index 0000000..ece51ea
--- /dev/null
+++ b/Student/stephen/lesson02/featuresdf.csv
@@ -0,0 +1,101 @@
+id,name,artists,danceability,energy,key,loudness,mode,speechiness,acousticness,instrumentalness,liveness,valence,tempo,duration_ms,time_signature
+7qiZfU4dY1lWllzX7mPBI,Shape of You,Ed Sheeran,0.825,0.652,1.0,-3.183,0.0,0.0802,0.581,0.0,0.0931,0.931,95.977,233713.0,4.0
+5CtI0qwDJkDQGwXD1H1cL,Despacito - Remix,Luis Fonsi,0.694,0.815,2.0,-4.328,1.0,0.12,0.229,0.0,0.0924,0.813,88.931,228827.0,4.0
+4aWmUDTfIPGksMNLV2rQP,Despacito (Featuring Daddy Yankee),Luis Fonsi,0.66,0.786,2.0,-4.757,1.0,0.17,0.209,0.0,0.112,0.846,177.833,228200.0,4.0
+6RUKPb4LETWmmr3iAEQkt,Something Just Like This,The Chainsmokers,0.617,0.635,11.0,-6.769,0.0,0.0317,0.0498,1.44e-05,0.164,0.446,103.019,247160.0,4.0
+3DXncPQOG4VBw3QHh3S81,I'm the One,DJ Khaled,0.609,0.668,7.0,-4.284,1.0,0.0367,0.0552,0.0,0.167,0.811,80.924,288600.0,4.0
+7KXjTSCq5nL1LoYtL7XAw,HUMBLE.,Kendrick Lamar,0.904,0.611,1.0,-6.842,0.0,0.0888,0.000259,2.03e-05,0.0976,0.4,150.02,177000.0,4.0
+3eR23VReFzcdmS7TYCrhC,It Ain't Me (with Selena Gomez),Kygo,0.64,0.533,0.0,-6.596,1.0,0.0706,0.119,0.0,0.0864,0.515,99.968,220781.0,4.0
+3B54sVLJ402zGa6Xm4YGN,Unforgettable,French Montana,0.726,0.769,6.0,-5.043,1.0,0.123,0.0293,0.0101,0.104,0.733,97.985,233902.0,4.0
+0KKkJNfGyhkQ5aFogxQAP,That's What I Like,Bruno Mars,0.853,0.56,1.0,-4.961,1.0,0.0406,0.013,0.0,0.0944,0.86,134.066,206693.0,4.0
+3NdDpSvN911VPGivFlV5d,"I Don’t Wanna Live Forever (Fifty Shades Darker) - From ""Fifty Shades Darker (Original Motion Picture Soundtrack)""",ZAYN,0.735,0.451,0.0,-8.374,1.0,0.0585,0.0631,1.3e-05,0.325,0.0862,117.973,245200.0,4.0
+7GX5flRQZVHRAGd6B4TmD,XO TOUR Llif3,Lil Uzi Vert,0.732,0.75,11.0,-6.366,0.0,0.231,0.00264,0.0,0.109,0.401,155.096,182707.0,4.0
+72jbDTw1piOOj770jWNea,Paris,The Chainsmokers,0.653,0.658,2.0,-6.428,1.0,0.0304,0.0215,1.66e-06,0.0939,0.219,99.99,221507.0,4.0
+0dA2Mk56wEzDgegdC6R17,Stay (with Alessia Cara),Zedd,0.679,0.634,5.0,-5.024,0.0,0.0654,0.232,0.0,0.115,0.498,102.013,210091.0,4.0
+4iLqG9SeJSnt0cSPICSjx,Attention,Charlie Puth,0.774,0.626,3.0,-4.432,0.0,0.0432,0.0969,3.12e-05,0.0848,0.777,100.041,211475.0,4.0
+0VgkVdmE4gld66l8iyGjg,Mask Off,Future,0.833,0.434,2.0,-8.795,1.0,0.431,0.0102,0.0219,0.165,0.281,150.062,204600.0,4.0
+3a1lNhkSLSkpJE4MSHpDu,Congratulations,Post Malone,0.627,0.812,6.0,-4.215,1.0,0.0358,0.198,0.0,0.212,0.504,123.071,220293.0,4.0
+6kex4EBAj0WHXDKZMEJaa,Swalla (feat. Nicki Minaj & Ty Dolla $ign),Jason Derulo,0.696,0.817,1.0,-3.862,1.0,0.109,0.075,0.0,0.187,0.782,98.064,216409.0,4.0
+6PCUP3dWmTjcTtXY02oFd,Castle on the Hill,Ed Sheeran,0.461,0.834,2.0,-4.868,1.0,0.0989,0.0232,1.14e-05,0.14,0.471,135.007,261154.0,4.0
+5knuzwU65gJK7IF5yJsua,Rockabye (feat. Sean Paul & Anne-Marie),Clean Bandit,0.72,0.763,9.0,-4.068,0.0,0.0523,0.406,0.0,0.18,0.742,101.965,251088.0,4.0
+0CcQNd8CINkwQfe1RDtGV,Believer,Imagine Dragons,0.779,0.787,10.0,-4.305,0.0,0.108,0.0524,0.0,0.14,0.708,124.982,204347.0,4.0
+2rb5MvYT7ZIxbKW5hfcHx,Mi Gente,J Balvin,0.543,0.677,11.0,-4.915,0.0,0.0993,0.0148,6.21e-06,0.13,0.294,103.809,189440.0,4.0
+0tKcYR2II1VCQWT79i5Nr,Thunder,Imagine Dragons,0.6,0.81,0.0,-4.749,1.0,0.0479,0.00683,0.21,0.155,0.298,167.88,187147.0,4.0
+5uCax9HTNlzGybIStD3vD,Say You Won't Let Go,James Arthur,0.358,0.557,10.0,-7.398,1.0,0.059,0.695,0.0,0.0902,0.494,85.043,211467.0,4.0
+79cuOz3SPQTuFrp8WgftA,There's Nothing Holdin' Me Back,Shawn Mendes,0.857,0.8,2.0,-4.035,1.0,0.0583,0.381,0.0,0.0913,0.966,121.996,199440.0,4.0
+6De0lHrwBfPfrhorm9q1X,Me Rehúso,Danny Ocean,0.744,0.804,1.0,-6.327,1.0,0.0677,0.0231,0.0,0.0494,0.426,104.823,205715.0,4.0
+6D0b04NJIKfEMg040WioJ,Issues,Julia Michaels,0.706,0.427,8.0,-6.864,1.0,0.0879,0.413,0.0,0.0609,0.42,113.804,176320.0,4.0
+0afhq8XCExXpqazXczTSv,Galway Girl,Ed Sheeran,0.624,0.876,9.0,-3.374,1.0,0.1,0.0735,0.0,0.327,0.781,99.943,170827.0,4.0
+3ebXMykcMXOcLeJ9xZ17X,Scared to Be Lonely,Martin Garrix,0.584,0.54,1.0,-7.786,0.0,0.0576,0.0895,0.0,0.261,0.195,137.972,220883.0,4.0
+7BKLCZ1jbUBVqRi2FVlTV,Closer,The Chainsmokers,0.748,0.524,8.0,-5.599,1.0,0.0338,0.414,0.0,0.111,0.661,95.01,244960.0,4.0
+1x5sYLZiu9r5E43kMlt9f,Symphony (feat. Zara Larsson),Clean Bandit,0.707,0.629,0.0,-4.581,0.0,0.0563,0.259,1.6e-05,0.138,0.457,122.863,212459.0,4.0
+5GXAXm5YOmYT0kL5jHvYB,I Feel It Coming,The Weeknd,0.768,0.813,0.0,-5.94,0.0,0.128,0.427,0.0,0.102,0.579,92.994,269187.0,4.0
+5aAx2yezTd8zXrkmtKl66,Starboy,The Weeknd,0.681,0.594,7.0,-7.028,1.0,0.282,0.165,3.49e-06,0.134,0.535,186.054,230453.0,4.0
+1OAh8uOEOvTDqkKFsKksC,Wild Thoughts,DJ Khaled,0.671,0.672,0.0,-3.094,0.0,0.0688,0.0329,0.0,0.118,0.632,97.98,204173.0,4.0
+7tr2za8SQg2CI8EDgrdtN,Slide,Calvin Harris,0.736,0.795,1.0,-3.299,0.0,0.0545,0.498,1.21e-06,0.254,0.511,104.066,230813.0,4.0
+2ekn2ttSfGqwhhate0LSR,New Rules,Dua Lipa,0.771,0.696,9.0,-6.258,0.0,0.0755,0.00256,9.71e-06,0.179,0.656,116.054,208827.0,4.0
+5tz69p7tJuGPeMGwNTxYu,1-800-273-8255,Logic,0.629,0.572,5.0,-7.733,0.0,0.0387,0.57,0.0,0.192,0.386,100.015,250173.0,4.0
+7hDc8b7IXETo14hHIHdnh,Passionfruit,Drake,0.809,0.463,11.0,-11.377,1.0,0.0396,0.256,0.085,0.109,0.364,111.98,298941.0,4.0
+7wGoVu4Dady5GV0Sv4UIs,rockstar,Post Malone,0.577,0.522,5.0,-6.594,0.0,0.0984,0.13,9.03e-05,0.142,0.119,159.772,218320.0,4.0
+6EpRaXYhGOB3fj4V2uDkM,Strip That Down,Liam Payne,0.869,0.485,6.0,-5.595,1.0,0.0545,0.246,0.0,0.0765,0.527,106.028,204502.0,4.0
+3A7qX2QjDlPnazUsRk5y0,2U (feat. Justin Bieber),David Guetta,0.548,0.65,8.0,-5.827,0.0,0.0591,0.219,0.0,0.225,0.557,144.937,194897.0,4.0
+0tgVpDi06FyKpA1z0VMD4,Perfect,Ed Sheeran,0.599,0.448,8.0,-6.312,1.0,0.0232,0.163,0.0,0.106,0.168,95.05,263400.0,3.0
+78rIJddV4X0HkNAInEcYd,Call On Me - Ryan Riback Extended Remix,Starley,0.676,0.843,0.0,-4.068,1.0,0.0367,0.0623,0.000752,0.181,0.718,105.003,222041.0,4.0
+5bcTCxgc7xVfSaMV3RuVk,Feels,Calvin Harris,0.893,0.745,11.0,-3.105,0.0,0.0571,0.0642,0.0,0.0943,0.872,101.018,223413.0,4.0
+0NiXXAI876aGImAd6rTj8,Mama,Jonas Blue,0.746,0.793,11.0,-4.209,0.0,0.0412,0.11,0.0,0.0528,0.557,104.027,181615.0,4.0
+0qYTZCo5Bwh1nsUFGZP3z,Felices los 4,Maluma,0.755,0.789,5.0,-4.502,1.0,0.146,0.231,0.0,0.351,0.737,93.973,229849.0,4.0
+2EEeOnHehOozLq4aS0n6S,iSpy (feat. Lil Yachty),KYLE,0.746,0.653,7.0,-6.745,1.0,0.289,0.378,0.0,0.229,0.672,75.016,253107.0,4.0
+152lZdxL1OR0ZMW6KquMi,Location,Khalid,0.736,0.449,1.0,-11.462,0.0,0.425,0.33,0.000162,0.0898,0.326,80.126,219080.0,4.0
+6mICuAdrwEjh6Y6lroV2K,Chantaje,Shakira,0.852,0.773,8.0,-2.921,0.0,0.0776,0.187,3.05e-05,0.159,0.907,102.034,195840.0,4.0
+4Km5HrUvYTaSUfiSGPJeQ,Bad and Boujee (feat. Lil Uzi Vert),Migos,0.927,0.665,11.0,-5.313,1.0,0.244,0.061,0.0,0.123,0.175,127.076,343150.0,4.0
+0ofbQMrRDsUaVKq2mGLEA,Havana,Camila Cabello,0.768,0.517,7.0,-4.323,0.0,0.0312,0.186,3.8e-05,0.104,0.418,104.992,216897.0,4.0
+6HUnnBwYZqcED1eQztxMB,Solo Dance,Martin Jensen,0.744,0.836,6.0,-2.396,0.0,0.0507,0.0435,0.0,0.194,0.36,114.965,174933.0,4.0
+343YBumqHu19cGoGARUTs,Fake Love,Drake,0.927,0.488,9.0,-9.433,0.0,0.42,0.108,0.0,0.196,0.605,133.987,210937.0,4.0
+4pdPtRcBmOSQDlJ3Fk945,Let Me Love You,DJ Snake,0.476,0.718,8.0,-5.309,1.0,0.0576,0.0784,1.02e-05,0.122,0.142,199.864,205947.0,4.0
+3PEgB3fkiojxms35ntsTg,More Than You Know,Axwell /\ Ingrosso,0.644,0.743,5.0,-5.002,0.0,0.0355,0.034,0.0,0.257,0.544,123.074,203000.0,4.0
+1xznGGDReH1oQq0xzbwXa,One Dance,Drake,0.791,0.619,1.0,-5.886,1.0,0.0532,0.00784,0.00423,0.351,0.371,103.989,173987.0,4.0
+7nKBxz47S9SD79N086fuh,SUBEME LA RADIO,Enrique Iglesias,0.684,0.823,9.0,-3.297,0.0,0.0773,0.0744,0.0,0.111,0.647,91.048,208163.0,4.0
+1NDxZ7cFAo481dtYWdrUn,Pretty Girl - Cheat Codes X CADE Remix,Maggie Lindemann,0.703,0.868,7.0,-4.661,0.0,0.0291,0.15,0.132,0.104,0.733,121.03,193613.0,4.0
+3m660poUr1chesgkkjQM7,Sorry Not Sorry,Demi Lovato,0.704,0.633,11.0,-6.923,0.0,0.241,0.0214,0.0,0.29,0.863,144.021,203760.0,4.0
+3kxfsdsCpFgN412fpnW85,Redbone,Childish Gambino,0.743,0.359,1.0,-10.401,1.0,0.0794,0.199,0.00611,0.137,0.587,160.083,326933.0,4.0
+6b8Be6ljOzmkOmFslEb23,24K Magic,Bruno Mars,0.818,0.803,1.0,-4.282,1.0,0.0797,0.034,0.0,0.153,0.632,106.97,225983.0,4.0
+6HZILIRieu8S0iqY8kIKh,DNA.,Kendrick Lamar,0.637,0.514,1.0,-6.763,1.0,0.365,0.0047,0.0,0.094,0.402,139.931,185947.0,4.0
+3umS4y3uQDkqekNjVpiRU,El Amante,Nicky Jam,0.683,0.691,8.0,-5.535,1.0,0.0432,0.243,0.0,0.14,0.732,179.91,219507.0,4.0
+00lNx0OcTJrS3MKHcB80H,You Don't Know Me - Radio Edit,Jax Jones,0.876,0.669,11.0,-6.054,0.0,0.138,0.163,0.0,0.185,0.682,124.007,213947.0,4.0
+6520aj0B4FSKGVuKNsOCO,Chained To The Rhythm,Katy Perry,0.448,0.801,0.0,-5.363,1.0,0.165,0.0733,0.0,0.146,0.462,189.798,237734.0,4.0
+1louJpMmzEicAn7lzDalP,No Promises (feat. Demi Lovato),Cheat Codes,0.741,0.667,10.0,-5.445,1.0,0.134,0.0575,0.0,0.106,0.595,112.956,223504.0,4.0
+2QbFClFyhMMtiurUjuQlA,Don't Wanna Know (feat. Kendrick Lamar),Maroon 5,0.775,0.617,7.0,-6.166,1.0,0.0701,0.341,0.0,0.0985,0.485,100.048,214265.0,4.0
+5hYTyyh2odQKphUbMqc5g,"How Far I'll Go - From ""Moana""",Alessia Cara,0.314,0.555,9.0,-9.601,1.0,0.37,0.157,0.000108,0.067,0.159,179.666,175517.0,4.0
+38yBBH2jacvDxrznF7h08,Slow Hands,Niall Horan,0.734,0.418,0.0,-6.678,1.0,0.0425,0.0129,0.0,0.0579,0.868,85.909,188174.0,4.0
+2cnKEkpVUSV4wnjQiTWfH,Escápate Conmigo,Wisin,0.747,0.864,8.0,-3.181,0.0,0.0599,0.0245,4.46e-05,0.0853,0.754,92.028,232787.0,4.0
+0SGkqnVQo9KPytSri1H6c,Bounce Back,Big Sean,0.77,0.567,2.0,-5.698,1.0,0.175,0.105,0.0,0.125,0.26,81.477,222360.0,4.0
+5Ohxk2dO5COHF1krpoPig,Sign of the Times,Harry Styles,0.516,0.595,5.0,-4.63,1.0,0.0313,0.0275,0.0,0.109,0.222,119.972,340707.0,4.0
+6gBFPUFcJLzWGx4lenP6h,goosebumps,Travis Scott,0.841,0.728,7.0,-3.37,1.0,0.0484,0.0847,0.0,0.149,0.43,130.049,243837.0,4.0
+5Z3GHaZ6ec9bsiI5Benrb,Young Dumb & Broke,Khalid,0.798,0.539,1.0,-6.351,1.0,0.0421,0.199,1.66e-05,0.165,0.394,136.949,202547.0,4.0
+6jA8HL9i4QGzsj6fjoxp8,There for You,Martin Garrix,0.611,0.644,6.0,-7.607,0.0,0.0553,0.124,0.0,0.124,0.13,105.969,221904.0,4.0
+21TdkDRXuAB3k90ujRU1e,Cold (feat. Future),Maroon 5,0.697,0.716,9.0,-6.288,0.0,0.113,0.118,0.0,0.0424,0.506,99.905,234308.0,4.0
+7vGuf3Y35N4wmASOKLUVV,Silence,Marshmello,0.52,0.761,4.0,-3.093,1.0,0.0853,0.256,4.96e-06,0.17,0.286,141.971,180823.0,4.0
+1mXVgsBdtIVeCLJnSnmtd,Too Good At Goodbyes,Sam Smith,0.698,0.375,5.0,-8.279,1.0,0.0491,0.652,0.0,0.173,0.534,91.92,201000.0,4.0
+3EmmCZoqpWOTY1g2GBwJo,Just Hold On,Steve Aoki,0.647,0.932,11.0,-3.515,1.0,0.0824,0.00383,1.5e-06,0.0574,0.374,114.991,198774.0,4.0
+6uFsE1JgZ20EXyU0JQZbU,Look What You Made Me Do,Taylor Swift,0.773,0.68,9.0,-6.378,0.0,0.141,0.213,1.57e-05,0.122,0.497,128.062,211859.0,4.0
+0CokSRCu5hZgPxcZBaEzV,Glorious (feat. Skylar Grey),Macklemore,0.731,0.794,0.0,-5.126,0.0,0.0522,0.0323,2.59e-05,0.112,0.356,139.994,220454.0,4.0
+6875MeXyCW0wLyT72Eetm,Starving,Hailee Steinfeld,0.721,0.626,4.0,-4.2,1.0,0.123,0.402,0.0,0.102,0.558,99.914,181933.0,4.0
+3AEZUABDXNtecAOSC1qTf,Reggaetón Lento (Bailemos),CNCO,0.761,0.838,4.0,-3.073,0.0,0.0502,0.4,0.0,0.176,0.71,93.974,222560.0,4.0
+3E2Zh20GDCR9B1EYjfXWy,Weak,AJR,0.673,0.637,5.0,-4.518,1.0,0.0429,0.137,0.0,0.184,0.678,123.98,201160.0,4.0
+4pLwZjInHj3SimIyN9SnO,Side To Side,Ariana Grande,0.648,0.738,6.0,-5.883,0.0,0.247,0.0408,0.0,0.292,0.603,159.145,226160.0,4.0
+3QwBODjSEzelZyVjxPOHd,Otra Vez (feat. J Balvin),Zion & Lennox,0.832,0.772,10.0,-5.429,1.0,0.1,0.0559,0.000486,0.44,0.704,96.016,209453.0,4.0
+1wjzFQodRWrPcQ0AnYnvQ,I Like Me Better,Lauv,0.752,0.505,9.0,-7.621,1.0,0.253,0.535,2.55e-06,0.104,0.419,91.97,197437.0,4.0
+04DwTuZ2VBdJCCC5TROn7,In the Name of Love,Martin Garrix,0.49,0.485,4.0,-6.237,0.0,0.0406,0.0592,0.0,0.337,0.196,133.889,195840.0,4.0
+6DNtNfH8hXkqOX1sjqmI7,Cold Water (feat. Justin Bieber & MØ),Major Lazer,0.608,0.798,6.0,-5.092,0.0,0.0432,0.0736,0.0,0.156,0.501,92.943,185352.0,4.0
+1UZOjK1BwmwWU14Erba9C,Malibu,Miley Cyrus,0.573,0.781,8.0,-6.406,1.0,0.0555,0.0767,2.64e-05,0.0813,0.343,139.934,231907.0,4.0
+4b4KcovePX8Ke2cLIQTLM,All Night,The Vamps,0.544,0.809,8.0,-5.098,1.0,0.0363,0.0038,0.0,0.323,0.448,145.017,197640.0,4.0
+1a5Yu5L18qNxVhXx38njO,Hear Me Now,Alok,0.789,0.442,11.0,-7.844,1.0,0.0421,0.586,0.00366,0.0927,0.45,121.971,192846.0,4.0
+4c2W3VKsOFoIg2SFaO6DY,Your Song,Rita Ora,0.855,0.624,1.0,-4.093,1.0,0.0488,0.158,0.0,0.0513,0.962,117.959,180757.0,4.0
+22eADXu8DfOAUEDw4vU8q,Ahora Dice,Chris Jeday,0.708,0.693,6.0,-5.516,1.0,0.138,0.246,0.0,0.129,0.427,143.965,271080.0,4.0
+7nZmah2llfvLDiUjm0kiy,Friends (with BloodPop®),Justin Bieber,0.744,0.739,8.0,-5.35,1.0,0.0387,0.00459,0.0,0.306,0.649,104.99,189467.0,4.0
+2fQrGHiQOvpL9UgPvtYy6,Bank Account,21 Savage,0.884,0.346,8.0,-8.228,0.0,0.351,0.0151,7.04e-06,0.0871,0.376,75.016,220307.0,4.0
+1PSBzsahR2AKwLJgx8ehB,Bad Things (with Camila Cabello),Machine Gun Kelly,0.675,0.69,2.0,-4.761,1.0,0.132,0.21,0.0,0.287,0.272,137.817,239293.0,4.0
+0QsvXIfqM0zZoerQfsI9l,Don't Let Me Down,The Chainsmokers,0.542,0.859,11.0,-5.651,1.0,0.197,0.16,0.00466,0.137,0.403,159.797,208053.0,4.0
+7mldq42yDuxiUNn08nvzH,Body Like A Back Road,Sam Hunt,0.731,0.469,5.0,-7.226,1.0,0.0326,0.463,1.04e-06,0.103,0.631,98.963,165387.0,4.0
+7i2DJ88J7jQ8K7zqFX2fW,Now Or Never,Halsey,0.658,0.588,6.0,-4.902,0.0,0.0367,0.105,1.28e-06,0.125,0.434,110.075,214802.0,4.0
+1j4kHkkpqZRBwE0A4CN4Y,Dusk Till Dawn - Radio Edit,ZAYN,0.258,0.437,11.0,-6.593,0.0,0.039,0.101,1.27e-06,0.106,0.0967,180.043,239000.0,4.0
diff --git a/Student/stephen/lesson02/lesson02_assignment.py b/Student/stephen/lesson02/lesson02_assignment.py
new file mode 100644
index 0000000..16f4a81
--- /dev/null
+++ b/Student/stephen/lesson02/lesson02_assignment.py
@@ -0,0 +1,65 @@
+import pandas as pd
+
+
+music = pd.read_csv("featuresdf.csv")
+
+
+songlist = zip(music.name, music.artists)
+
+# Generator
+def fav_generator(artist, songlist):
+ return ((artists, name) for name, artists in songlist if artist in artists)
+
+ed_sheeran = fav_generator("Ed Sheeran", songlist)
+
+# print Ed Sheeran songs using generator
+while True:
+ try:
+ print(next(ed_sheeran))
+ except StopIteration:
+ break
+
+# Output:
+# ('Ed Sheeran', 'Shape of You')
+# ('Ed Sheeran', 'Castle on the Hill')
+# ('Ed Sheeran', 'Galway Girl')
+# ('Ed Sheeran', 'Perfect')
+
+
+
+# Closure
+tracklist = zip(music.artists, music.name, music.energy)
+
+def energy(tracklist):
+ def filtered_list(threshold):
+ for name, artists, energy in tracklist:
+ if energy >= threshold:
+ print(name, ', ', artists, ', ', energy)
+ return [(artists, name, energy) for name, artists, energy in tracklist if energy >= threshold]
+ return filtered_list
+
+
+high_energy = energy(tracklist)
+high_energy(0.8)
+
+# Output:
+# Luis Fonsi , Despacito - Remix , 0.815
+# Post Malone , Congratulations , 0.812
+# Jason Derulo , Swalla (feat. Nicki Minaj & Ty Dolla $ign) , 0.8170000000000001
+# Ed Sheeran , Castle on the Hill , 0.8340000000000001
+# Imagine Dragons , Thunder , 0.81
+# Shawn Mendes , There's Nothing Holdin' Me Back , 0.8
+# Danny Ocean , Me Rehúso , 0.804
+# Ed Sheeran , Galway Girl , 0.8759999999999999
+# The Weeknd , I Feel It Coming , 0.813
+# Starley , Call On Me - Ryan Riback Extended Remix , 0.843
+# Martin Jensen , Solo Dance , 0.836
+# Enrique Iglesias , SUBEME LA RADIO , 0.823
+# Maggie Lindemann , Pretty Girl - Cheat Codes X CADE Remix , 0.868
+# Bruno Mars , 24K Magic , 0.8029999999999999
+# Katy Perry , Chained To The Rhythm , 0.8009999999999999
+# Wisin , Escápate Conmigo , 0.8640000000000001
+# Steve Aoki , Just Hold On , 0.932
+# CNCO , Reggaetón Lento (Bailemos) , 0.838
+# The Vamps , All Night , 0.809
+# The Chainsmokers , Don't Let Me Down , 0.8590000000000001
diff --git a/Student/stephen/lesson03/Lesson03_Activity.py b/Student/stephen/lesson03/Lesson03_Activity.py
new file mode 100644
index 0000000..17e085b
--- /dev/null
+++ b/Student/stephen/lesson03/Lesson03_Activity.py
@@ -0,0 +1,97 @@
+
+# coding: utf-8
+
+# In[6]:
+
+
+## Null wrapper decorators
+def null_decorator(funct):
+ funct
+
+
+# In[8]:
+
+
+@null_decorator
+def greet():
+ return 'Hello!'
+
+
+# In[9]:
+
+
+class my_decorator(object):
+
+ def __init__(self, f):
+ print()
+
+
+# In[11]:
+
+
+## Context managers
+
+
+# Think of them like cleaners use with statement to bind all your relevant commands. They close connections that are open when you are done. The moment you have a with, it handles the closing of the connection, the cashing, etc.
+#
+# There are two methods to benefit from context manager functionality:
+# __enter__() and __exit__()
+
+# In[12]:
+
+
+## Recursions
+## need a base case and a recursion case
+
+
+# In[14]:
+
+
+## >>> from factorial import factorial
+## >>> factorial(4)
+
+def factorial(n):
+ if n==1:
+ return 1
+ return n*factorial(n-1)
+
+
+# In[15]:
+
+
+factorial(3)
+
+
+# In[16]:
+
+
+factorial(10)
+
+
+# In[17]:
+
+
+factorial(10) / factorial(9)
+
+
+# Many people are familiar with recursion but not backtracking.
+# Backtracking is when you have a node with multiple options which in turn have multiple options (a tree like structure) and you are trying all options until you find a path with the shortest length.
+
+# In[18]:
+
+
+def permute(list, s):
+ if list == 1:
+ return s
+ else:
+ return [ y + x
+ for y in permute(1, s)
+ for x in permute(list - 1, s)
+ ]
+
+
+# In[21]:
+
+
+permute(3, ['1','2','5'])
+
diff --git a/Student/stephen/lesson03/ballard_locks.py b/Student/stephen/lesson03/ballard_locks.py
new file mode 100644
index 0000000..29403f4
--- /dev/null
+++ b/Student/stephen/lesson03/ballard_locks.py
@@ -0,0 +1,58 @@
+# Sequence:
+# "Stopping the pumps."
+# "Opening the doors."
+# "Closing the doors."
+# "Restarting the pumps."
+
+
+
+class Locke(object):
+ """
+ From Doug Hellmann, PyMOTW
+ https://pymotw.com/3/contextlib/#module-contextlib
+ """
+
+ def __init__(self, boat_limit):
+ self.boat_limit = boat_limit
+
+ def move_boats_through(self, boats):
+ if boats > self.boat_limit:
+ raise RuntimeError('Too many boats!')
+ else:
+ print('Opening the doors.')
+
+ def __enter__(self):
+ print('Stopping the pumps.')
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ if exc_type is RuntimeError:
+ print(exc_val)
+ else:
+ print('Closing the doors.')
+ print('Restarting the pumps.')
+ return self
+
+small_locke = Locke(5)
+large_locke = Locke(10)
+boats = 8
+
+# Too many boats through a small locke will raise an exception
+print('Testing small_locke using 8 boats.')
+with small_locke as locke:
+ locke.move_boats_through(boats)
+
+# A lock with sufficient capacity can move boats without incident.
+print('Testing large_locke using 8 boats.')
+with large_locke as locke:
+ locke.move_boats_through(boats)
+
+# Results:
+# Testing small_locke using 8 boats.
+# Stopping the pumps.
+# Too many boats!
+# Testing large_locke using 8 boats.
+# Stopping the pumps.
+# Opening the doors.
+# Closing the doors.
+# Restarting the pumps.
\ No newline at end of file
diff --git a/Student/stephen/lesson03/factorial.py b/Student/stephen/lesson03/factorial.py
new file mode 100644
index 0000000..5540549
--- /dev/null
+++ b/Student/stephen/lesson03/factorial.py
@@ -0,0 +1,17 @@
+## >>> from factorial import factorial
+## >>> factorial(4)
+
+def factorial(n):
+ if n==1:
+ return 1
+ return n*factorial(n-1)
+
+# Tests:
+# In [2]: factorial(10)
+# Out[2]: 3628800
+
+# In [3]: factorial(5)
+# Out[3]: 120
+
+# In [4]: factorial(5) / factorial(3)
+# Out[4]: 20.0
\ No newline at end of file
diff --git a/Student/stephen/lesson04/Lesson 4.ipynb b/Student/stephen/lesson04/Lesson 4.ipynb
new file mode 100644
index 0000000..140806b
--- /dev/null
+++ b/Student/stephen/lesson04/Lesson 4.ipynb
@@ -0,0 +1,640 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## Exercise #1\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "b\n",
+ "a\n"
+ ]
+ }
+ ],
+ "source": [
+ "def a(func):\n",
+ " print('a')\n",
+ " return func\n",
+ "\n",
+ "def b(func):\n",
+ " print('b')\n",
+ " return func\n",
+ "\n",
+ "# sugar syntax (syntactic sugar)\n",
+ "@a\n",
+ "@b\n",
+ "def foo():\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## Did you know b printed before a?\n",
+ "## That's because the decorator closest to def will be called first\n",
+ "## Then its return value is passed to the 1st decorator\n",
+ "## Eventually, the return value of the topmost decorator will be \n",
+ "## assigned to the function's name in the containing scope"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## Exercise #2\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class Bla(object):\n",
+ " \n",
+ " ## Staticmethod signature\n",
+ " @staticmethod\n",
+ " def f(arg1, arg2, arg3, etc)\n",
+ "\n",
+ " ## classmethod signature\n",
+ " ## takes the class as one of the parameters\n",
+ " @classmethod\n",
+ " def f(cls, arg1, arg2, arg3, etc)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## Demo of @classmethod and @staticmethod\n",
+ "## These are built in decorators"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class Date(object):\n",
+ "\n",
+ " def __init__(self, day=0, month=0, year=0):\n",
+ " self.day = day\n",
+ " self.month = month\n",
+ " self.year = year\n",
+ "\n",
+ " @classmethod\n",
+ " def from_string(cls, date_as_string):\n",
+ " day, month, year = map(int, date_as_string.split('-'))\n",
+ " date1 = cls(day, month, year)\n",
+ " return date1\n",
+ "\n",
+ " @staticmethod\n",
+ " def is_date_valid(date_as_string):\n",
+ " day, month, year = map(int, date_as_string.split('-'))\n",
+ " return day <= 31 and month <= 12 and year <= 3999\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "date2 = Date.from_string('06-04-2018')\n",
+ "is_date = Date.is_date_valid('06-05-2018')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "<__main__.Date object at 0x000001F348317EF0>\n"
+ ]
+ }
+ ],
+ "source": [
+ "print (date2)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "True\n"
+ ]
+ }
+ ],
+ "source": [
+ "## Note this is only checks the format of the date string not the accuracy\n",
+ "## of the date .\n",
+ "print(is_date)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "Exercise #3\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class Awesome(object):\n",
+ " def fu(self,x):\n",
+ " print (\"About to execute fu(%s,%s)\"%(self,x))\n",
+ "\n",
+ " @classmethod\n",
+ " def class_fu(cls,x):\n",
+ " print (\"About to execute class_fu(%s,%s)\"%(cls,x))\n",
+ "\n",
+ " @staticmethod\n",
+ " def static_fu(x):\n",
+ " print (\"executing static_fu(%s)\"%x) \n",
+ "\n",
+ "myobj=Awesome() "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## usual way an object instance calls a method. \n",
+ "## The object instance, myobj, is implicitly passed as the first argument.\n",
+ "## \n",
+ "myobj.fu(1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## @staticmethod\n",
+ "\n",
+ "## Lets do how @staticmethod works\n",
+ "## neither self (the object instance) nor cls (the class) is implicitly \n",
+ "## passed as the first argument. They behave like plain functions except \n",
+ "## that you can call them from an instance or the class:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "myobj.static_fu(1)\n",
+ "# executing static_fu(1)\n",
+ "\n",
+ "Awesome.static_fu('I am awesome')\n",
+ "# executing static_fu('I am Awesome')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## Staticmethods are used to group functions which have some logical \n",
+ "## connection with a class to the class.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "##Classmethod\n",
+ "## the class of the object instance is implicitly passed as the first \n",
+ "## argument instead of self.\n",
+ "\n",
+ "myobj.class_fu(1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## You can also call class_fu using the class. \n",
+ "## If you define something to be a classmethod, it is probably \n",
+ "## because you intend to call it from the class rather than from a \n",
+ "## class instance. \n",
+ "\n",
+ "## Note the following\n",
+ "## Awesome.fu(1) would have raised a TypeError, \n",
+ "## but Awesome.class_fu(1) works just fine:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "Awesome.fu(1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "Awesome.class_fu(1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## End of classmethod\n",
+ "\n",
+ "## To note\n",
+ "## fu expects 2 arguments, while myobj.fu only expects 1 argument.\n",
+ "## myobj is bound to fu\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(myobj.fu)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## With myobj.class_fu, myobj is not bound to class_fu, rather the class \n",
+ "## Awesome is bound to class_fu.\n",
+ "\n",
+ "print(Awesome.class_fu)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## Here, with a staticmethod, even though it is a method, \n",
+ "## myobj.static_fu just returns with no arguments \n",
+ "## bound. static_fu expects 1 argument, and myobj.static_fu expects \n",
+ "## 1 argument too.\n",
+ "\n",
+ "print(myobj.static_fu)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## Exercise 4\n",
+ "\n",
+ "## getattr () example"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class Person():\n",
+ " name = 'Wayne'\n",
+ " def say(self, what):\n",
+ " print(self.name, what)\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Wayne'"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "getattr(Person, 'name')\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "attr_name = 'name'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "person = Person()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Wayne'"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "getattr(person, attr_name)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Wayne Welcome to Python 220\n"
+ ]
+ }
+ ],
+ "source": [
+ "getattr(person, 'say')('Welcome to Python 220')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "AttributeError",
+ "evalue": "'Person' object has no attribute 'age'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;31m## getattr will raise AttributeError if attribute\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;31m## with the given name does not exist in the object:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mgetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mperson\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'age'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mAttributeError\u001b[0m: 'Person' object has no attribute 'age'"
+ ]
+ }
+ ],
+ "source": [
+ "## getattr will raise AttributeError if attribute \n",
+ "## with the given name does not exist in the object:\n",
+ "getattr(person, 'age')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## Exercise 5\n",
+ "\n",
+ "## setattr()\n",
+ "\n",
+ "setattr(person, 'name', 'Tamara')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Tamara'"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "## accessing the instance attribute\n",
+ "person.name"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Wayne'"
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "## accessing the class attribute\n",
+ "Person.name\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " \n"
+ ]
+ }
+ ],
+ "source": [
+ "## Exercise 6\n",
+ "\n",
+ "## type Class\n",
+ "## applying \"type\" to an object returns the class of which the object \n",
+ "## is an instance of\n",
+ "x = [1, 2, 3]\n",
+ "y = \"Hello Py 220 Class\"\n",
+ "print(type(x), type(y))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## object x is an instance of class list\n",
+ "## object y is an instance of class str\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " \n"
+ ]
+ }
+ ],
+ "source": [
+ "## If you apply type on the name of a \n",
+ "## class itself, you get the class \"type\" returned.\n",
+ "\n",
+ "print(type(list), type(str))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " \n",
+ " \n"
+ ]
+ }
+ ],
+ "source": [
+ "## Above command is same as \n",
+ "\n",
+ "print(type(x), type(y))\n",
+ "print(type(type(x)), type(type(y)))\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "## A user-defined class (or the class \"object\") is an instance of the \n",
+ "## class \"type\". So, we can see, that classes are created from type. \n",
+ "## In Python3 there is no difference between \"classes\" and \"types\". \n",
+ "## They are in most cases used as synonyms.\n",
+ "\n",
+ "\n",
+ "## The fact that classes are instances of a class \"type\" allows us to \n",
+ "## program metaclasses. We can create classes, which inherit from the class \n",
+ "## \"type\". So, a metaclass is a subclass of the class \"type\".\n",
+ "\n",
+ "## Enter Metaclasses\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/Student/stephen/lesson04/__init__.py b/Student/stephen/lesson04/__init__.py
new file mode 100644
index 0000000..db59bd9
--- /dev/null
+++ b/Student/stephen/lesson04/__init__.py
@@ -0,0 +1,8 @@
+"""
+json_save package
+
+Pulling in names from the other packages.
+"""
+
+__version__ = "0.4.0"
+
diff --git a/Student/stephen/lesson04/__pycache__/mailroom_meta.cpython-36.pyc b/Student/stephen/lesson04/__pycache__/mailroom_meta.cpython-36.pyc
new file mode 100644
index 0000000..1539732
Binary files /dev/null and b/Student/stephen/lesson04/__pycache__/mailroom_meta.cpython-36.pyc differ
diff --git a/Student/stephen/lesson04/donor_db.json b/Student/stephen/lesson04/donor_db.json
new file mode 100644
index 0000000..f86d85d
--- /dev/null
+++ b/Student/stephen/lesson04/donor_db.json
@@ -0,0 +1,73 @@
+{
+ "__obj_type": "DonorDB",
+ "_donors": {
+ "elmer fudd": {
+ "__obj_type": "Donor",
+ "_name": "Elmer Fudd",
+ "_donations": [
+ 200.0,
+ 45.0,
+ 75.0
+ ]
+ },
+ "elon musk": {
+ "__obj_type": "Donor",
+ "_name": "Elon Musk",
+ "_donations": [
+ 16,
+ 68,
+ 170,
+ 425
+ ]
+ },
+ "jeff bezos": {
+ "__obj_type": "Donor",
+ "_name": "Jeff Bezos",
+ "_donations": [
+ 50,
+ 100,
+ 56,
+ 600.0
+ ]
+ },
+ "mark zuckerberg": {
+ "__obj_type": "Donor",
+ "_name": "Mark Zuckerberg",
+ "_donations": [
+ 45,
+ 105,
+ 349,
+ 101,
+ 78
+ ]
+ },
+ "paul allen": {
+ "__obj_type": "Donor",
+ "_name": "Paul Allen",
+ "_donations": [
+ 10,
+ 50,
+ 400,
+ 400
+ ]
+ },
+ "richard branson": {
+ "__obj_type": "Donor",
+ "_name": "Richard Branson",
+ "_donations": [
+ 25,
+ 90,
+ 124,
+ 300
+ ]
+ },
+ "oprah winfrey": {
+ "__obj_type": "Donor",
+ "_name": "Oprah Winfrey",
+ "_donations": [
+ 1000.0,
+ 200.0
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/Student/stephen/lesson04/json_save/.DS_Store b/Student/stephen/lesson04/json_save/.DS_Store
new file mode 100644
index 0000000..c3ac046
Binary files /dev/null and b/Student/stephen/lesson04/json_save/.DS_Store differ
diff --git a/Student/stephen/lesson04/json_save/__init__.py b/Student/stephen/lesson04/json_save/__init__.py
new file mode 100644
index 0000000..db59bd9
--- /dev/null
+++ b/Student/stephen/lesson04/json_save/__init__.py
@@ -0,0 +1,8 @@
+"""
+json_save package
+
+Pulling in names from the other packages.
+"""
+
+__version__ = "0.4.0"
+
diff --git a/Student/stephen/lesson04/json_save/__pycache__/__init__.cpython-36.pyc b/Student/stephen/lesson04/json_save/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000..71b199b
Binary files /dev/null and b/Student/stephen/lesson04/json_save/__pycache__/__init__.cpython-36.pyc differ
diff --git a/Student/stephen/lesson04/json_save/__pycache__/json_save_meta.cpython-36.pyc b/Student/stephen/lesson04/json_save/__pycache__/json_save_meta.cpython-36.pyc
new file mode 100644
index 0000000..112df81
Binary files /dev/null and b/Student/stephen/lesson04/json_save/__pycache__/json_save_meta.cpython-36.pyc differ
diff --git a/Student/stephen/lesson04/json_save/__pycache__/saveables.cpython-36.pyc b/Student/stephen/lesson04/json_save/__pycache__/saveables.cpython-36.pyc
new file mode 100644
index 0000000..b4ae68a
Binary files /dev/null and b/Student/stephen/lesson04/json_save/__pycache__/saveables.cpython-36.pyc differ
diff --git a/Student/stephen/lesson04/json_save/json_save_dec.py b/Student/stephen/lesson04/json_save/json_save_dec.py
new file mode 100644
index 0000000..5af4de9
--- /dev/null
+++ b/Student/stephen/lesson04/json_save/json_save_dec.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+
+"""
+json_save implemented as a decorator
+"""
+
+import json
+from pathlib import Path
+
+from .json_save_meta import *
+
+
+# assorted methods that will need to be added to the decorated class:
+def _to_json_compat(self):
+ """
+ converts this object to a json-compatible dict.
+
+ returns the dict
+ """
+ # add and __obj_type attribute, so it can be reconstructed
+ dic = {"__obj_type": self.__class__.__qualname__}
+ for attr, typ in self._attrs_to_save.items():
+ dic[attr] = typ.to_json_compat(getattr(self, attr))
+ return dic
+
+
+def __eq__(self, other):
+ """
+ default equality method that checks if all of the saved attributes
+ are equal
+ """
+ for attr in self._attrs_to_save:
+ try:
+ if getattr(self, attr) != getattr(other, attr):
+ return False
+ except AttributeError:
+ return False
+ return True
+
+@classmethod
+def _from_json_dict(cls, dic):
+ """
+ creates an instance of this class populated by the contents of
+ the json compatible dict
+
+ the object is created with __new__ before setting the attributes
+
+ NOTE: __init__ is not called.
+ There should not be any extra initialization required in __init__
+ """
+ # create a new object
+ obj = cls.__new__(cls)
+ for attr, typ in cls._attrs_to_save.items():
+ setattr(obj, attr, typ.to_python(dic[attr]))
+ return obj
+
+
+def __new__(cls, *args, **kwargs):
+ """
+ This adds instance attributes to assure they are all there, even if
+ they are not set in the subclasses __init__
+
+ it's in __new__ so that it will get called before the decorated class'
+ __init__ -- the __init__ will override anything here.
+ """
+ # create the instance by calling the base class __new__
+ obj = cls.__base__.__new__(cls)
+ # using super() did not work here -- why??
+ # set the instance attributes to defaults
+ for attr, typ in cls._attrs_to_save.items():
+ setattr(obj, attr, typ.default)
+ return obj
+
+
+def _to_json(self, fp=None, indent=4):
+ """
+ Converts the object to JSON
+
+ :param fp=None: an open file_like object to write the json to.
+ If it is None, then a string with the JSON
+ will be returned as a string
+
+ :param indent=4: The indentation level desired in the JSON
+ """
+ if fp is None:
+ return json.dumps(self.to_json_compat(), indent=indent)
+ else:
+ json.dump(self.to_json_compat(), fp, indent=indent)
+
+
+# now the actual decorator
+def json_save(cls):
+ """
+ json_save decorator
+
+ makes decorated classes Saveable to json
+ """
+ # make sure this is decorating a class object
+ if type(cls) is not type:
+ raise TypeError("json_save can only be used on classes")
+
+ # find the saveable attributes
+ # these will the attributes that get saved and reconstructed from json.
+ # each class object gets its own dict
+ attr_dict = vars(cls)
+ cls._attrs_to_save = {}
+ for key, attr in attr_dict.items():
+ if isinstance(attr, Saveable):
+ cls._attrs_to_save[key] = attr
+ if not cls._attrs_to_save:
+ raise TypeError(f"{cls.__name__} class has no saveable attributes.\n"
+ " Note that Savable attributes must be instances")
+ # register this class so we can re-construct instances.
+ Saveable.ALL_SAVEABLES[cls.__qualname__] = cls
+
+ # add the methods:
+ cls.__new__ = __new__
+ cls.to_json_compat = _to_json_compat
+ cls.__eq__ = __eq__
+ cls.from_json_dict = _from_json_dict
+ cls.to_json = _to_json
+
+ return cls
+
+
+# utilities for loading arbitrary objects from json
+def from_json_dict(j_dict):
+ """
+ factory function that creates an arbitrary JsonSaveable
+ object from a json-compatible dict.
+ """
+ # determine the class it is.
+ obj_type = j_dict["__obj_type"]
+ obj = Saveable.ALL_SAVEABLES[obj_type].from_json_dict(j_dict)
+ return obj
+
+
+def from_json(_json):
+ """
+ Factory function that re-creates a JsonSaveable object
+ from a json string or file
+ """
+ if isinstance(_json, (str, Path)):
+ return from_json_dict(json.loads(_json))
+ else: # assume a file-like object
+ return from_json_dict(json.load(_json))
diff --git a/Student/stephen/lesson04/json_save/json_save_meta.py b/Student/stephen/lesson04/json_save/json_save_meta.py
new file mode 100644
index 0000000..5207d9b
--- /dev/null
+++ b/Student/stephen/lesson04/json_save/json_save_meta.py
@@ -0,0 +1,227 @@
+#!/usr/bin/env python3
+
+"""
+json_save
+
+metaclass based system for saving objects in a JSON format
+
+This could be useful, but it's kept simple to show the use of metaclasses
+
+The idea is that you subclass from JsonSavable, and then you get an object
+that be saved and reloaded to/from JSON
+"""
+
+import json
+
+# import * is a bad idea in general, but helpful for a modules that's part
+# of a package, where you control the names.
+from .saveables import *
+
+
+class MetaJsonSaveable(type):
+ """
+ The metaclass for creating JsonSavable classes
+
+ Deriving from type makes it a metaclass.
+
+ Note: the __init__ gets run at compile time, not run time.
+ (module import time)
+ """
+ def __init__(cls, name, bases, attr_dict):
+ # it gets the class object as the first param.
+ # and then the same parameters as the type() factory function
+
+ # you want to call the regular type initilizer:
+ super().__init__(name, bases, attr_dict)
+
+ # here's where we work with the class attributes:
+ # these will the attributes that get saved and reconstructed from json.
+ # each class object gets its own dict
+ cls._attrs_to_save = {}
+ for key, attr in attr_dict.items():
+ if isinstance(attr, Saveable):
+ cls._attrs_to_save[key] = attr
+ # special case JsonSaveable -- no attrs to save yet
+ if cls.__name__ != "JsonSaveable" and (not cls._attrs_to_save):
+ raise TypeError(f"{cls.__name__} class has no saveable attributes.\n"
+ " Note that Savable attributes must be instances")
+
+ # register this class so we can re-construct instances.
+ Saveable.ALL_SAVEABLES[attr_dict["__qualname__"]] = cls
+
+
+class JsonSaveable(metaclass=MetaJsonSaveable):
+ """
+ mixin for JsonSavable objects
+ """
+ def __new__(cls, *args, **kwargs):
+ """
+ This adds instance attributes to assure they are all there, even if
+ they are not set in the subclasses __init__
+ """
+ # create the instance
+ obj = super().__new__(cls)
+ # set the instance attributes to defaults
+ for attr, typ in cls._attrs_to_save.items():
+ setattr(obj, attr, typ.default)
+ return obj
+
+ def __eq__(self, other):
+ """
+ default equality method that checks if all of the saved attributes
+ are equal
+ """
+ for attr in self._attrs_to_save:
+ try:
+ if getattr(self, attr) != getattr(other, attr):
+ return False
+ except AttributeError:
+ return False
+ return True
+
+ def to_json_compat(self):
+ """
+ converts this object to a json-compatible dict.
+
+ returns the dict
+ """
+ # add and __obj_type attribute, so it can be reconstructed
+ dic = {"__obj_type": self.__class__.__qualname__}
+ for attr, typ in self._attrs_to_save.items():
+ dic[attr] = typ.to_json_compat(getattr(self, attr))
+ return dic
+
+ @classmethod
+ def from_json_dict(cls, dic):
+ """
+ creates an instance of this class populated by the contents of
+ the json compatible dict
+
+ the object is created with __new__ before setting the attributes
+
+ NOTE: __init__ is not called.
+ There should not be any extra initialization required in __init__
+ """
+ # create a new object
+ obj = cls.__new__(cls)
+ for attr, typ in cls._attrs_to_save.items():
+ setattr(obj, attr, typ.to_python(dic[attr]))
+ # make sure it gets initialized
+ # obj.__init__()
+ return obj
+
+ @classmethod
+ def from_json_file(cls, fp):
+ """
+ creates an instance of this class populated by the contents of
+ a json file
+
+ """
+ # create a new object
+ dic = json.load(fp)
+ obj = cls.__new__(cls)
+ for attr, typ in cls._attrs_to_save.items():
+ setattr(obj, attr, typ.to_python(dic[attr]))
+ # make sure it gets initialized
+ # obj.__init__()
+ return obj
+
+ def to_json(self, fp=None, indent=4):
+ """
+ Converts the object to JSON
+
+ :param fp=None: an open file_like object to write the json to.
+ If it is None, then a string with the JSON
+ will be returned as a string
+
+ :param indent=4: The indentation level desired in the JSON
+ """
+ if fp is None:
+ return json.dumps(self.to_json_compat(), indent=indent)
+ else:
+ json.dump(self.to_json_compat(), fp, indent=indent)
+
+ def __str__(self):
+ msg = ["{} object, with attributes:".format(self.__class__.__qualname__)]
+ for attr in self._attrs_to_save.keys():
+ msg.append("{}: {}".format(attr, getattr(self, attr)))
+ return "\n".join(msg)
+
+
+def from_json_dict(j_dict):
+ """
+ factory function that creates an arbitrary JsonSavable
+ object from a json-compatible dict.
+ """
+ # determine the class it is.
+ obj_type = j_dict["__obj_type"]
+ obj = Saveable.ALL_SAVEABLES[obj_type].from_json_dict(j_dict)
+ return obj
+
+
+def from_json(_json):
+ """
+ factory function that re-creates a JsonSavable object
+ from a json string or file
+ """
+ if isinstance(_json, str):
+ return from_json_dict(json.loads(_json))
+ else: # assume a file-like object
+ return from_json_dict(json.load(_json))
+
+
+if __name__ == "__main__":
+
+ # Example of using it.
+ class MyClass(JsonSaveable):
+
+ x = Int()
+ y = Float()
+ l = List()
+
+ def __init__(self, x, lst):
+ self.x = x
+ self.lst = lst
+
+
+ class OtherSaveable(JsonSaveable):
+
+ foo = String()
+ bar = Int()
+
+ def __init__(self, foo, bar):
+ self.foo = foo
+ self.bar = bar
+
+ # create one:
+ print("about to create a instance")
+ mc = MyClass(5, [3, 5, 7, 9])
+
+ print(mc)
+
+ jc = mc.to_json_compat()
+
+ # re-create it from the dict:
+ mc2 = MyClass.from_json_dict(jc)
+
+ print(mc2 == "fred")
+
+ assert mc2 == mc
+
+ print(mc.to_json())
+
+ # now try it nested...
+ mc_nest = MyClass(34, [OtherSaveable("this", 2),
+ OtherSaveable("that", 64),
+ ])
+
+ mc_nest_comp = mc_nest.to_json_compat()
+ print(mc_nest_comp)
+
+ # can we re-create it?
+ mc_nest2 = MyClass.from_json_dict(mc_nest_comp)
+
+ print(mc_nest)
+ print(mc_nest2)
+
+ assert mc_nest == mc_nest2
diff --git a/Student/stephen/lesson04/json_save/saveables.py b/Student/stephen/lesson04/json_save/saveables.py
new file mode 100644
index 0000000..16ac75f
--- /dev/null
+++ b/Student/stephen/lesson04/json_save/saveables.py
@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+
+"""
+The Saveable objects used by both the metaclass and decorator approach.
+"""
+import ast
+
+# import json
+
+__all__ = ['Bool',
+ 'Dict',
+ 'Float',
+ 'Int',
+ 'List',
+ 'Saveable',
+ 'String',
+ 'Tuple',
+ ]
+
+
+class Saveable():
+ """
+ Base class for all saveable types
+ """
+ default = None
+ ALL_SAVEABLES = {}
+
+ @staticmethod
+ def to_json_compat(val):
+ """
+ returns a json-compatible version of val
+
+ should be overridden in saveable types that are not json compatible.
+ """
+ return val
+
+ @staticmethod
+ def to_python(val):
+ """
+ convert from a json compatible version to the python version
+
+ Must be overridden if not a one-to-one match
+
+ This is where validation could be added as well.
+ """
+ return val
+
+
+class String(Saveable):
+ """
+ A Saveable string
+
+ Strings are the same in JSON as Python, so nothing to do here
+ """
+ default = ""
+
+
+class Bool(Saveable):
+ """
+ A Saveable boolean
+
+ Booleans are pretty much the same in JSON as Python, so nothing to do here
+ """
+ default = False
+
+
+class Int(Saveable):
+
+ """
+ A Saveable integer
+
+ Integers are a little different in JSON than Python. Strictly speaking
+ JSON only has "numbers", which can be integer or float, so a little to
+ do here to make sure we get an int in Python.
+ """
+
+ default = 0
+
+ @staticmethod
+ def to_python(val):
+ """
+ Convert a number to a python integer
+ """
+ return int(val)
+
+
+class Float(Saveable):
+ """
+ A Saveable floating point number
+
+ floats are a little different in JSON than Python. Strictly speaking
+ JSON only has "numbers", which can be integer or float, so a little to
+ do here to make sure we get a float in Python.
+ """
+
+ default = 0.0
+
+ @staticmethod
+ def to_python(val):
+ """
+ Convert a number to a python float
+ """
+ return float(val)
+
+# Container types: these need to hold Saveable objects.
+
+
+class Tuple(Saveable):
+ """
+ This assumes that whatever is in the tuple is Saveable or a "usual"
+ type: numbers, strings.
+ """
+ default = ()
+
+ @staticmethod
+ def to_python(val):
+ """
+ Convert a list to a tuple -- json only has one array type,
+ which matches to a list.
+ """
+ # simply uses the List to_python method -- that part is the same.
+ return tuple(List.to_python(val))
+
+
+class List(Saveable):
+ """
+ This assumes that whatever is in the list is Saveable or a "usual"
+ type: numbers, strings.
+ """
+ default = []
+
+ @staticmethod
+ def to_json_compat(val):
+ lst = []
+ for item in val:
+ try:
+ lst.append(item.to_json_compat())
+ except AttributeError:
+ lst.append(item)
+ return lst
+
+ @staticmethod
+ def to_python(val):
+ """
+ Convert an array to a list.
+
+ Complicated because list may contain non-json-compatible objects
+ """
+ # try to reconstitute using the obj method
+ new_list = []
+ for item in val:
+ try:
+ obj_type = item["__obj_type"]
+ obj = Saveable.ALL_SAVEABLES[obj_type].from_json_dict(item)
+ new_list.append(obj)
+ except (TypeError, KeyError):
+ new_list.append(item)
+ return new_list
+
+
+class Dict(Saveable):
+ """
+ This assumes that whatever in the dict is Saveable as well.
+
+ This supports non-string keys, but all keys must be the same type.
+ """
+ default = {}
+
+ @staticmethod
+ def to_json_compat(val):
+ d = {}
+ # first key, arbitrarily
+ key_type = type(next(iter(val.keys())))
+ if key_type is not str:
+ # need to add key_type to json
+ d['__key_not_string'] = True
+ key_not_string = True
+ else:
+ key_not_string = False
+ for key, item in val.items():
+ kis = type(key) is str
+ if ((kis and key_not_string) or (not (kis or key_not_string))):
+ raise TypeError("dict keys must be all strings or no strings")
+ if key_type is not str:
+ # convert key to string
+ s_key = repr(key)
+ # make sure it can be reconstituted
+ if ast.literal_eval(s_key) != key:
+ raise ValueError(f"json save cannot save dicts with key:{key}")
+ else:
+ s_key = key
+ try:
+ d[s_key] = item.to_json_compat()
+ except AttributeError:
+ d[s_key] = item
+ return d
+
+ @staticmethod
+ def to_python(val):
+ """
+ Convert a json object to a dict
+
+ Complicated because object may contain non-json-compatible objects
+ """
+
+ # try to reconstitute using the obj method
+ new_dict = {}
+ key_not_string = val.pop('__key_not_string', False)
+ for key, item in val.items():
+ if key_not_string:
+ key = ast.literal_eval(key)
+ try:
+ obj_type = item["__obj_type"]
+ obj = Saveable.ALL_SAVEABLES[obj_type].from_json_dict(item)
+ new_dict[key] = obj
+ except (KeyError, TypeError):
+ new_dict[key] = item
+ return new_dict
diff --git a/Student/stephen/lesson04/json_save/test/.DS_Store b/Student/stephen/lesson04/json_save/test/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/Student/stephen/lesson04/json_save/test/.DS_Store differ
diff --git a/Student/stephen/lesson04/json_save/test/__init__.py b/Student/stephen/lesson04/json_save/test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/Student/stephen/lesson04/json_save/test/temp.json b/Student/stephen/lesson04/json_save/test/temp.json
new file mode 100644
index 0000000..760c652
--- /dev/null
+++ b/Student/stephen/lesson04/json_save/test/temp.json
@@ -0,0 +1,21 @@
+{
+ "__obj_type": "ClassWithList",
+ "x": 34,
+ "lst": [
+ {
+ "__obj_type": "SimpleClass",
+ "a": 3,
+ "b": 4.5
+ },
+ {
+ "__obj_type": "SimpleClass",
+ "a": 100,
+ "b": 5.2
+ },
+ {
+ "__obj_type": "SimpleClass",
+ "a": 34,
+ "b": 89.1
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Student/stephen/lesson04/json_save/test/test_json_save_dec.py b/Student/stephen/lesson04/json_save/test/test_json_save_dec.py
new file mode 100644
index 0000000..f587517
--- /dev/null
+++ b/Student/stephen/lesson04/json_save/test/test_json_save_dec.py
@@ -0,0 +1,256 @@
+#!/usr/bin/env python
+
+"""
+test code for the decorator version of json_save
+"""
+
+import pytest
+
+import json_save.json_save_dec as js
+
+
+# Some simple classes to test:
+
+@js.json_save
+class NoInit:
+ """
+ A class with saveable attribute, but no __init__
+ """
+ x = js.Int()
+ y = js.String()
+
+
+@js.json_save
+class SimpleClass:
+
+ a = js.Int()
+ b = js.Float()
+
+ def __init__(self, a=None, b=None):
+ if a is not None:
+ self.a = a
+ if b is not None:
+ self.b = b
+
+
+@js.json_save
+class ClassWithList:
+
+ x = js.Int()
+ lst = js.List()
+
+ def __init__(self, x, lst):
+ self.x = x
+ self.lst = lst
+
+
+@js.json_save
+class ClassWithDict:
+ x = js.Int()
+ d = js.Dict()
+
+ def __init__(self, x, d):
+ self.x = x
+ self.d = d
+
+
+@pytest.fixture
+def nested_example():
+ l = [SimpleClass(3, 4.5),
+ SimpleClass(100, 5.2),
+ SimpleClass(34, 89.1),
+ ]
+
+ return ClassWithList(34, l)
+
+@pytest.fixture
+def nested_dict():
+ d = {'this': SimpleClass(3, 4.5),
+ 'that': SimpleClass(100, 5.2),
+ 'other': SimpleClass(34, 89.1),
+ }
+
+ return ClassWithDict(34, d)
+
+
+# now the actual test code
+
+def test_hasattr():
+ """
+ checks that the default attributes get set if they are not created by an __init__
+ """
+ ts = NoInit()
+ # has the instance attributes even though no __init__ exists
+ # they should be the default values
+ assert ts.x == 0
+ assert ts.y == ""
+
+
+def test_attrs():
+ ts = SimpleClass()
+
+ attrs = ts._attrs_to_save
+ assert list(attrs.keys()) == ['a', 'b']
+
+
+def test_simple_save():
+
+ ts = SimpleClass()
+ ts.a = 5
+ ts.b = 3.14
+
+ saved = ts.to_json_compat()
+ assert saved['a'] == 5
+ assert saved['b'] == 3.14
+ assert saved['__obj_type'] == 'SimpleClass'
+
+
+def test_list_attr():
+
+ cwl = ClassWithList(10, [1, 5, 2, 8])
+
+ saved = cwl.to_json_compat()
+ assert saved['x'] == 10
+ assert saved['lst'] == [1, 5, 2, 8]
+ assert saved['__obj_type'] == 'ClassWithList'
+
+
+def test_nested(nested_example):
+
+ saved = nested_example.to_json_compat()
+
+ assert saved['x'] == 34
+ assert len(saved['lst']) == 3
+ for obj in saved['lst']:
+ assert obj['__obj_type'] == 'SimpleClass'
+
+
+def test_save_load_simple():
+ sc = SimpleClass(5, 3.14)
+
+ jc = sc.to_json_compat()
+
+ # re-create it from the dict:
+ sc2 = SimpleClass.from_json_dict(jc)
+
+ assert sc == sc2
+
+
+def test_save_load_nested(nested_example):
+
+ jc = nested_example.to_json_compat()
+
+ # re-create it from the dict:
+ nested_example2 = ClassWithList.from_json_dict(jc)
+
+ assert nested_example == nested_example2
+
+
+def test_from_json_dict(nested_example):
+
+ j_dict = nested_example.to_json_compat()
+
+ reconstructed = js.from_json_dict(j_dict)
+
+ assert reconstructed == nested_example
+
+
+def test_from_json(nested_example):
+ """
+ can it be re-created from an actual json string?
+ """
+
+ json_str = nested_example.to_json()
+
+ reconstructed = js.from_json(json_str)
+
+ assert reconstructed == nested_example
+
+
+def test_from_json_file(nested_example):
+ """
+ can it be re-created from an actual json file?
+ """
+
+ json_str = nested_example.to_json()
+ with open("temp.json", 'w') as tempfile:
+ tempfile.write(nested_example.to_json())
+
+ with open("temp.json") as tempfile:
+ reconstructed = js.from_json(tempfile)
+
+ reconstructed = js.from_json(json_str)
+
+ assert reconstructed == nested_example
+
+
+def test_dict():
+ """
+ a simple class with a dict attribute
+ """
+ cwd = ClassWithDict(45, {"this": 34, "that": 12})
+
+ # see if it can be reconstructed
+
+ jc = cwd.to_json_compat()
+
+ # re-create it from the dict:
+ cwd2 = ClassWithDict.from_json_dict(jc)
+
+ assert cwd == cwd2
+
+
+def test_from_json_dict2(nested_dict):
+ """
+ can it be re-created from an actual json string?
+ """
+
+ json_str = nested_dict.to_json()
+ reconstructed = js.from_json(json_str)
+
+ assert reconstructed == nested_dict
+
+
+def test_eq():
+ sc1 = SimpleClass(3, 4.5)
+ sc2 = SimpleClass(3, 4.5)
+
+ assert sc1 == sc2
+
+
+def test_not_eq():
+ sc1 = SimpleClass(3, 4.5)
+ sc2 = SimpleClass(3, 4.4)
+
+ assert sc1 != sc2
+
+
+def test_not_eq_reconstruct():
+ sc1 = SimpleClass.from_json_dict(SimpleClass(3, 4.5).to_json_compat())
+ sc2 = SimpleClass.from_json_dict(SimpleClass(2, 4.5).to_json_compat())
+
+ assert sc1 != sc2
+ assert sc2 != sc1
+
+
+def test_not_valid():
+ """
+ You should get an error trying to make a savable class with
+ no savable attributes.
+ """
+ with pytest.raises(TypeError):
+ @js.json_save
+ class NotValid():
+ pass
+
+
+def test_not_valid_class_not_instance():
+ """
+ You should get an error trying to make a savable class with
+ no savable attributes.
+ """
+ with pytest.raises(TypeError):
+ @js.json_save
+ class NotValid():
+ a = js.Int
+ b = js.Float
diff --git a/Student/stephen/lesson04/json_save/test/test_json_save_meta.py b/Student/stephen/lesson04/json_save/test/test_json_save_meta.py
new file mode 100644
index 0000000..2f42c22
--- /dev/null
+++ b/Student/stephen/lesson04/json_save/test/test_json_save_meta.py
@@ -0,0 +1,235 @@
+#!/usr/bin/env python3
+
+"""
+tests for json_save
+"""
+
+import json_save.json_save_meta as js
+
+import pytest
+
+
+class NoInit(js.JsonSaveable):
+ x = js.Int()
+ y = js.String()
+
+
+# A few simple examples to test
+class SimpleClass(js.JsonSaveable):
+
+ a = js.Int()
+ b = js.Float()
+
+ def __init__(self, a=None, b=None):
+ if a is not None:
+ self.a = a
+ if b is not None:
+ self.b = b
+
+
+class ClassWithList(js.JsonSaveable):
+
+ x = js.Int()
+ lst = js.List()
+
+ def __init__(self, x, lst):
+ self.x = x
+ self.lst = lst
+
+
+class ClassWithDict(js.JsonSaveable):
+ x = js.Int()
+ d = js.Dict()
+
+ def __init__(self, x, d):
+ self.x = x
+ self.d = d
+
+
+@pytest.fixture
+def nested_example():
+ lst = [SimpleClass(3, 4.5),
+ SimpleClass(100, 5.2),
+ SimpleClass(34, 89.1),
+ ]
+
+ return ClassWithList(34, lst)
+
+
+@pytest.fixture
+def nested_dict():
+ d = {'this': SimpleClass(3, 4.5),
+ 'that': SimpleClass(100, 5.2),
+ 'other': SimpleClass(34, 89.1),
+ }
+
+ return ClassWithDict(34, d)
+
+
+def test_hasattr():
+ ts = NoInit()
+ # has the attributes even though no __init__ exists
+ # they should be the default values
+ assert ts.x == 0
+ assert ts.y == ""
+
+
+def test_simple_save():
+
+ ts = SimpleClass()
+ ts.a = 5
+ ts.b = 3.14
+
+ saved = ts.to_json_compat()
+ assert saved['a'] == 5
+ assert saved['b'] == 3.14
+ assert saved['__obj_type'] == 'SimpleClass'
+
+
+def test_list_attr():
+
+ cwl = ClassWithList(10, [1, 5, 2, 8])
+
+ saved = cwl.to_json_compat()
+ assert saved['x'] == 10
+ assert saved['lst'] == [1, 5, 2, 8]
+ assert saved['__obj_type'] == 'ClassWithList'
+
+
+def test_nested(nested_example):
+
+ saved = nested_example.to_json_compat()
+
+ assert saved['x'] == 34
+ assert len(saved['lst']) == 3
+ for obj in saved['lst']:
+ assert obj['__obj_type'] == 'SimpleClass'
+
+
+def test_save_load_simple():
+ sc = SimpleClass(5, 3.14)
+
+ jc = sc.to_json_compat()
+
+ # re-create it from the dict:
+ sc2 = SimpleClass.from_json_dict(jc)
+
+ assert sc == sc2
+
+
+def test_save_load_nested(nested_example):
+
+ jc = nested_example.to_json_compat()
+
+ # re-create it from the dict:
+ nested_example2 = ClassWithList.from_json_dict(jc)
+
+ assert nested_example == nested_example2
+
+
+def test_from_json_dict(nested_example):
+
+ j_dict = nested_example.to_json_compat()
+
+ reconstructed = js.from_json_dict(j_dict)
+
+ assert reconstructed == nested_example
+
+
+def test_from_json(nested_example):
+ """
+ can it be re-created from an actual json string?
+ """
+
+ json_str = nested_example.to_json()
+
+ reconstructed = js.from_json(json_str)
+
+ assert reconstructed == nested_example
+
+
+def test_from_json_file(nested_example):
+ """
+ can it be re-created from an actual json file?
+ """
+
+ json_str = nested_example.to_json()
+ with open("temp.json", 'w') as tempfile:
+ tempfile.write(nested_example.to_json())
+
+ with open("temp.json") as tempfile:
+ reconstructed = js.from_json(tempfile)
+
+ reconstructed = js.from_json(json_str)
+
+ assert reconstructed == nested_example
+
+
+def test_dict():
+ """
+ a simple class with a dict attribute
+ """
+ cwd = ClassWithDict(45, {"this": 34, "that": 12})
+
+ # see if it can be reconstructed
+
+ jc = cwd.to_json_compat()
+
+ # re-create it from the dict:
+ cwd2 = ClassWithDict.from_json_dict(jc)
+
+ assert cwd == cwd2
+
+
+def test_from_json_dict2(nested_dict):
+ """
+ can it be re-created from an actual json string?
+ """
+
+ json_str = nested_dict.to_json()
+
+ reconstructed = js.from_json(json_str)
+
+ assert reconstructed == nested_dict
+
+def test_eq():
+ sc1 = SimpleClass(3, 4.5)
+ sc2 = SimpleClass(3, 4.5)
+
+ assert sc1 == sc2
+
+
+def test_not_eq():
+ sc1 = SimpleClass(3, 4.5)
+ sc2 = SimpleClass(3, 4.4)
+
+ assert sc1 != sc2
+
+
+def test_not_eq_reconstruct():
+ sc1 = SimpleClass.from_json_dict(SimpleClass(3, 4.5).to_json_compat())
+ sc2 = SimpleClass.from_json_dict(SimpleClass(2, 4.5).to_json_compat())
+
+ assert sc1 != sc2
+ assert sc2 != sc1
+
+
+def test_not_valid():
+ """
+ You should get an error trying to make a savable class with
+ no savable attributes.
+ """
+ with pytest.raises(TypeError):
+ class NotValid(js.JsonSaveable):
+ pass
+
+
+def test_not_valid_class_not_instance():
+ """
+ You should get an error trying to make a savable class with
+ no savable attributes.
+ """
+ with pytest.raises(TypeError):
+ class NotValid(js.JsonSaveable):
+ a = js.Int
+ b = js.Float
diff --git a/Student/stephen/lesson04/json_save/test/test_savables.py b/Student/stephen/lesson04/json_save/test/test_savables.py
new file mode 100644
index 0000000..831374c
--- /dev/null
+++ b/Student/stephen/lesson04/json_save/test/test_savables.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+
+"""
+tests for the savable objects
+"""
+import pytest
+
+import json
+
+from json_save.saveables import *
+
+# The simple, almost json <-> python ones:
+# Type, default, example
+basics = [(String, "This is a string"),
+ (Int, 23),
+ (Float, 3.1458),
+ (Bool, True),
+ (Bool, False),
+ (List, [2, 3, 4]),
+ (Tuple, (1, 2, 3.4, "this")),
+ (List, [[1, 2, 3], [4, 5, 6]]),
+ (List, [{"3": 34}, {"4": 5}]), # list with dicts in it.
+ (Dict, {"this": {"3": 34}, "that": {"4": 5}}) # dict with dicts
+ ]
+
+
+@pytest.mark.parametrize(('Type', 'val'), basics)
+def test_basics(Type, val):
+ js = json.dumps(Type.to_json_compat(val))
+ val2 = Type.to_python(json.loads(js))
+ assert val == val2
+ assert type(val) == type(val2)
+
+
+nested = [(List, [(1, 2), (3, 4), (5, 6)]), # tuple in list
+ (Tuple, ((1, 2), (3, 4), (5, 6))), # tuple in tuple
+ ]
+
+
+# This maybe should be fixed in the future??
+@pytest.mark.xfail(reason="nested not-standard types not supported")
+@pytest.mark.parametrize(('Type', 'val'), nested)
+def test_nested(Type, val):
+ print("original value:", val)
+ js = json.dumps(Type.to_json_compat(val))
+ print("js is:", js)
+ val2 = Type.to_python(json.loads(js))
+ print("new value is:", val2)
+ assert val == val2
+ assert type(val) == type(val2)
+
+
+
+
+dicts = [{"this": 14, "that": 1.23},
+ {34: 15, 23: 5},
+ {3.4: "float_key", 1.2: "float_key"},
+ {(1, 2, 3): "tuple_key"},
+ {(3, 4, 5): "tuple_int", ("this", "that"): "tuple_str"},
+ {4: "int_key", 1.23: "float_key", (1, 2, 3): "tuple_key"},
+ ]
+
+
+@pytest.mark.parametrize('val', dicts)
+def test_dicts(val):
+ js = json.dumps(Dict.to_json_compat(val))
+ val2 = Dict.to_python(json.loads(js))
+ assert val == val2
+ assert type(val) == type(val2)
+ # check that the types of the keys is the same
+ for k1, k2 in zip(val.keys(), val2.keys()):
+ assert type(k1) is type(k2)
+
+
+# These are dicts that can't be saved
+# -- mixing string and non-string keys
+bad_dicts = [{"this": "string_key", 4: "int_key"},
+ {3: "int_key", "this": "string_key"},
+ {None: "none_key", "this": "string_key"},
+ {"this": "string_key", None: "none_key"},
+ ]
+
+
+@pytest.mark.parametrize("val", bad_dicts)
+def test_bad_dicts(val):
+ with pytest.raises(TypeError):
+ Dict.to_json_compat(val)
diff --git a/Student/stephen/lesson04/lesson04_activity.ipynb b/Student/stephen/lesson04/lesson04_activity.ipynb
new file mode 100644
index 0000000..8ae2cf3
--- /dev/null
+++ b/Student/stephen/lesson04/lesson04_activity.ipynb
@@ -0,0 +1,1580 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Metaprogramming\n",
+ "\n",
+ "Like a decorator, wrapper that changes the behavior of another program.\n",
+ "\n",
+ "Fundamental premise is eliminating copy and paste\n",
+ "\n",
+ "Eliminating repeatable steps.\n",
+ "\n",
+ "What do you call a decorator that doesn't change anything? Null decorator"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Namespaces (LEGB):\n",
+ " Local\n",
+ " Enclosed (Nonlocal)\n",
+ " Global\n",
+ " Built-in\n",
+ " \n",
+ "\n",
+ "Global\n",
+ "Local\n",
+ "Builtin\n",
+ "Open\n",
+ "Enclosed"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class C:\n",
+ " a_class_attribute = 0\n",
+ " \n",
+ " def __init__(self):\n",
+ " self.an_instance_attribute = 0"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "c = C()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a_class_attribute',\n",
+ " 'an_instance_attribute']"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "dir(c) # looks at all the attributes of the class instance"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a_class_attribute']"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "dir(C)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'an_instance_attribute': 0}"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars(c) # only gives instance attributes"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "mappingproxy({'__module__': '__main__',\n",
+ " 'a_class_attribute': 0,\n",
+ " '__init__': ,\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None})"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars(C) # gives the class attributes"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Bad idea to manipulate the Global namespace in a class/function"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Namespaces are usually updatable dictionaries\n",
+ "vars should return the objects namespace (not a copy)\n",
+ "Classes have a mappying type that prevents updating\n",
+ "\n",
+ "__dict__ is a special attribute, a namespace updatable object\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class C:\n",
+ " a = 5\n",
+ " b = 6\n",
+ " \n",
+ " def __init__(self):\n",
+ " self.x = 32\n",
+ " self.y = 64"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "mappingproxy({'__module__': '__main__',\n",
+ " 'a': 5,\n",
+ " 'b': 6,\n",
+ " '__init__': ,\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None})"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars(C)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "c = C()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'x': 32, 'y': 64}"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars(c)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dict_keys(['__module__', 'a', 'b', '__init__', '__dict__', '__weakref__', '__doc__'])"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars(C).keys()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a',\n",
+ " 'b']"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "dir(C)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a',\n",
+ " 'b',\n",
+ " 'x',\n",
+ " 'y']"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "dir(c)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'__name__': '__main__',\n",
+ " '__doc__': 'Automatically created module for IPython interactive environment',\n",
+ " '__package__': None,\n",
+ " '__loader__': None,\n",
+ " '__spec__': None,\n",
+ " '__builtin__': ,\n",
+ " '__builtins__': ,\n",
+ " '_ih': ['',\n",
+ " 'class C:\\n a_class_attribute = 0\\n def __init__(self):\\n self.an_instance_attribute = 0',\n",
+ " 'class C:\\n a_class_attribute = 0\\n def __init__(self):\\n self.an_instance_attribute = 0',\n",
+ " 'c = C()',\n",
+ " 'dir(c)',\n",
+ " 'dir(C)',\n",
+ " 'vars(c) # only gives instance attributes',\n",
+ " 'vars(c) # only gives instance attributes',\n",
+ " 'vars(C) #',\n",
+ " 'class C:\\n a = 5\\n b = 6\\n \\n def __init__(self):\\n self.x = 32\\n self.y = 64',\n",
+ " 'vars(C)',\n",
+ " 'c = C()',\n",
+ " 'vars(c)',\n",
+ " 'vars(C).keys()',\n",
+ " 'dir(C)',\n",
+ " 'dir(c)',\n",
+ " 'vars()'],\n",
+ " '_oh': {4: ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a_class_attribute',\n",
+ " 'an_instance_attribute'],\n",
+ " 5: ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a_class_attribute'],\n",
+ " 6: {'an_instance_attribute': 0},\n",
+ " 7: {'an_instance_attribute': 0},\n",
+ " 8: mappingproxy({'__module__': '__main__',\n",
+ " 'a_class_attribute': 0,\n",
+ " '__init__': ,\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None}),\n",
+ " 10: mappingproxy({'__module__': '__main__',\n",
+ " 'a': 5,\n",
+ " 'b': 6,\n",
+ " '__init__': ,\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None}),\n",
+ " 12: {'x': 32, 'y': 64},\n",
+ " 13: dict_keys(['__module__', 'a', 'b', '__init__', '__dict__', '__weakref__', '__doc__']),\n",
+ " 14: ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a',\n",
+ " 'b'],\n",
+ " 15: ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a',\n",
+ " 'b',\n",
+ " 'x',\n",
+ " 'y']},\n",
+ " '_dh': ['C:\\\\Users\\\\ssouk\\\\Documents\\\\Python\\\\Python Programming 220 AC\\\\Lesson04'],\n",
+ " 'In': ['',\n",
+ " 'class C:\\n a_class_attribute = 0\\n def __init__(self):\\n self.an_instance_attribute = 0',\n",
+ " 'class C:\\n a_class_attribute = 0\\n def __init__(self):\\n self.an_instance_attribute = 0',\n",
+ " 'c = C()',\n",
+ " 'dir(c)',\n",
+ " 'dir(C)',\n",
+ " 'vars(c) # only gives instance attributes',\n",
+ " 'vars(c) # only gives instance attributes',\n",
+ " 'vars(C) #',\n",
+ " 'class C:\\n a = 5\\n b = 6\\n \\n def __init__(self):\\n self.x = 32\\n self.y = 64',\n",
+ " 'vars(C)',\n",
+ " 'c = C()',\n",
+ " 'vars(c)',\n",
+ " 'vars(C).keys()',\n",
+ " 'dir(C)',\n",
+ " 'dir(c)',\n",
+ " 'vars()'],\n",
+ " 'Out': {4: ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a_class_attribute',\n",
+ " 'an_instance_attribute'],\n",
+ " 5: ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a_class_attribute'],\n",
+ " 6: {'an_instance_attribute': 0},\n",
+ " 7: {'an_instance_attribute': 0},\n",
+ " 8: mappingproxy({'__module__': '__main__',\n",
+ " 'a_class_attribute': 0,\n",
+ " '__init__': ,\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None}),\n",
+ " 10: mappingproxy({'__module__': '__main__',\n",
+ " 'a': 5,\n",
+ " 'b': 6,\n",
+ " '__init__': ,\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None}),\n",
+ " 12: {'x': 32, 'y': 64},\n",
+ " 13: dict_keys(['__module__', 'a', 'b', '__init__', '__dict__', '__weakref__', '__doc__']),\n",
+ " 14: ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a',\n",
+ " 'b'],\n",
+ " 15: ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a',\n",
+ " 'b',\n",
+ " 'x',\n",
+ " 'y']},\n",
+ " 'get_ipython': >,\n",
+ " 'exit': ,\n",
+ " 'quit': ,\n",
+ " '_': ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a',\n",
+ " 'b',\n",
+ " 'x',\n",
+ " 'y'],\n",
+ " '__': ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a',\n",
+ " 'b'],\n",
+ " '___': dict_keys(['__module__', 'a', 'b', '__init__', '__dict__', '__weakref__', '__doc__']),\n",
+ " '_i': 'dir(c)',\n",
+ " '_ii': 'dir(C)',\n",
+ " '_iii': 'vars(C).keys()',\n",
+ " '_i1': 'class C:\\n a_class_attribute = 0\\n def __init__(self):\\n self.an_instance_attribute = 0',\n",
+ " '_i2': 'class C:\\n a_class_attribute = 0\\n def __init__(self):\\n self.an_instance_attribute = 0',\n",
+ " 'C': __main__.C,\n",
+ " '_i3': 'c = C()',\n",
+ " 'c': <__main__.C at 0x1ffc3833550>,\n",
+ " '_i4': 'dir(c)',\n",
+ " '_4': ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a_class_attribute',\n",
+ " 'an_instance_attribute'],\n",
+ " '_i5': 'dir(C)',\n",
+ " '_5': ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a_class_attribute'],\n",
+ " '_i6': 'vars(c) # only gives instance attributes',\n",
+ " '_6': {'an_instance_attribute': 0},\n",
+ " '_i7': 'vars(c) # only gives instance attributes',\n",
+ " '_7': {'an_instance_attribute': 0},\n",
+ " '_i8': 'vars(C) #',\n",
+ " '_8': mappingproxy({'__module__': '__main__',\n",
+ " 'a_class_attribute': 0,\n",
+ " '__init__': ,\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None}),\n",
+ " '_i9': 'class C:\\n a = 5\\n b = 6\\n \\n def __init__(self):\\n self.x = 32\\n self.y = 64',\n",
+ " '_i10': 'vars(C)',\n",
+ " '_10': mappingproxy({'__module__': '__main__',\n",
+ " 'a': 5,\n",
+ " 'b': 6,\n",
+ " '__init__': ,\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None}),\n",
+ " '_i11': 'c = C()',\n",
+ " '_i12': 'vars(c)',\n",
+ " '_12': {'x': 32, 'y': 64},\n",
+ " '_i13': 'vars(C).keys()',\n",
+ " '_13': dict_keys(['__module__', 'a', 'b', '__init__', '__dict__', '__weakref__', '__doc__']),\n",
+ " '_i14': 'dir(C)',\n",
+ " '_14': ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a',\n",
+ " 'b'],\n",
+ " '_i15': 'dir(c)',\n",
+ " '_15': ['__class__',\n",
+ " '__delattr__',\n",
+ " '__dict__',\n",
+ " '__dir__',\n",
+ " '__doc__',\n",
+ " '__eq__',\n",
+ " '__format__',\n",
+ " '__ge__',\n",
+ " '__getattribute__',\n",
+ " '__gt__',\n",
+ " '__hash__',\n",
+ " '__init__',\n",
+ " '__init_subclass__',\n",
+ " '__le__',\n",
+ " '__lt__',\n",
+ " '__module__',\n",
+ " '__ne__',\n",
+ " '__new__',\n",
+ " '__reduce__',\n",
+ " '__reduce_ex__',\n",
+ " '__repr__',\n",
+ " '__setattr__',\n",
+ " '__sizeof__',\n",
+ " '__str__',\n",
+ " '__subclasshook__',\n",
+ " '__weakref__',\n",
+ " 'a',\n",
+ " 'b',\n",
+ " 'x',\n",
+ " 'y'],\n",
+ " '_i16': 'vars()'}"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars() # returns the namespase of the local namespace"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "local_ns = vars()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "local_ns['fred'] = 'something'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'something'"
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fred"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fred = 'something else'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'something else'"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "fred"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'something else'"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "local_ns['fred']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# can access local namespace two separate ways"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "cns = vars(C)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "mappingproxy({'__module__': '__main__',\n",
+ " 'a': 5,\n",
+ " 'b': 6,\n",
+ " '__init__': ,\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None})"
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cns"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "TypeError",
+ "evalue": "'mappingproxy' object does not support item assignment",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mcns\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'fred'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m'something'\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mTypeError\u001b[0m: 'mappingproxy' object does not support item assignment"
+ ]
+ }
+ ],
+ "source": [
+ "cns['fred'] = 'something'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "C.fred = \"something\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'something'"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "cns['fred']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# if you add an attribute in the usual way you can add a new attribute to a Class namespace"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Metaprogramming\n",
+ "\n",
+ "Often misunderstood by developers\n",
+ "\n",
+ "[Instance]--<>-[Class]--<>--[Type]\n",
+ "\n",
+ "Metaclass is ability to create a special type of class that is a subset of class\n",
+ "\n",
+ "[Instance]--<>--[Class]--<>--{Metaclass]-->[Type]\n",
+ "\n",
+ "Metaclasses usually too risky to use\n",
+ "Can create conflicts\n",
+ "\n",
+ "Some scenarios where metaclasses are necessary\n",
+ "like in webprogramming like django\n",
+ "metaclasses are highly useful\n",
+ "\n",
+ "## Metaclass is a class of classes\n",
+ "\n",
+ "Type class is the most used type of metaclass\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class myClass(metaclass=type):\n",
+ " pass\n",
+ "\n",
+ "# default metaclass is type if not declared"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Metaprogram is a program that modifies programs\n",
+ "Everything is an OBJECT in python\n",
+ "that means everything can be created at run time and assigned to a variable/name\n",
+ "\n",
+ "OBJECT orientation of python Allows full introspcetion in metaprogramming\n",
+ "\n",
+ "Core introspection toolsare getattr() and setattr()\n",
+ "Also, delattr() used to delete attributes\n",
+ "\n",
+ "What's the difference between del and delattr()?\n",
+ "you can use del instead of delattr\n",
+ "\n",
+ "Can also use hasattr() to check for an attribute"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class Dummy:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "obj = Dummy"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "mappingproxy({'__module__': '__main__',\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None})"
+ ]
+ },
+ "execution_count": 34,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars(obj)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "setattr(obj, \"name\", \"Fred\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "mappingproxy({'__module__': '__main__',\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None,\n",
+ " 'name': 'Fred'})"
+ ]
+ },
+ "execution_count": 36,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars(obj)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Fred'"
+ ]
+ },
+ "execution_count": 37,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.name"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Fred'"
+ ]
+ },
+ "execution_count": 38,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "getattr(obj, \"name\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "delattr(obj, \"name\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "mappingproxy({'__module__': '__main__',\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None})"
+ ]
+ },
+ "execution_count": 40,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars(obj)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "AttributeError",
+ "evalue": "type object 'Dummy' has no attribute 'name'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mobj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mAttributeError\u001b[0m: type object 'Dummy' has no attribute 'name'"
+ ]
+ }
+ ],
+ "source": [
+ "obj.name"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "obj.name = \"fred\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'fred'"
+ ]
+ },
+ "execution_count": 43,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "obj.name"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "del obj.name"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "AttributeError",
+ "evalue": "type object 'Dummy' has no attribute 'name'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mobj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mAttributeError\u001b[0m: type object 'Dummy' has no attribute 'name'"
+ ]
+ }
+ ],
+ "source": [
+ "obj.name"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "setattr comes in handy when you don't know the attribute name, but you know the variable that points to the attribute"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "att_name = \"this\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "att_value = \"something\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "setattr(obj, att_name, att_value)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "mappingproxy({'__module__': '__main__',\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None,\n",
+ " 'this': 'something'})"
+ ]
+ },
+ "execution_count": 54,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars(obj)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "setattr(obj, 'this-that', 'something') #"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 56,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "mappingproxy({'__module__': '__main__',\n",
+ " '__dict__': ,\n",
+ " '__weakref__': ,\n",
+ " '__doc__': None,\n",
+ " 'this': 'something',\n",
+ " 'this-that': 'something'})"
+ ]
+ },
+ "execution_count": 56,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "vars(obj)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'that' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mobj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mthis\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mthat\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[1;31mNameError\u001b[0m: name 'that' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "obj.this-that #throws an error, but can use getattr()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'something'"
+ ]
+ },
+ "execution_count": 59,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "getattr(obj, 'this-that')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Default Built-in attributes exist for all objects\n",
+ "setattr and getattr allows you to manipulated the built-in attributes"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/Student/stephen/lesson04/mailroom_meta.py b/Student/stephen/lesson04/mailroom_meta.py
new file mode 100644
index 0000000..d82919b
--- /dev/null
+++ b/Student/stephen/lesson04/mailroom_meta.py
@@ -0,0 +1,265 @@
+#!/usr/bin/env python
+
+"""
+Simple Mailroom Program for a nonprofit
+"""
+
+# The script should prompt the user (you) to choose from a menu of 3 actions:
+# “Send a Thank You”, “Create a Report” or “quit”)
+
+import os, sys
+# import json
+import json_save.json_save_meta as js
+
+# Create a data object to store donor information
+# donors = {
+# 'Jeff Bezos': [50, 100, 56],
+# 'Mark Zuckerberg': [45, 105, 349, 101, 78],
+# 'Paul Allen': [10, 50, 400, 400],
+# 'Elon Musk': [16, 68, 170, 425],
+# 'Richard Branson': [25, 90, 124, 300]
+# }
+
+class Donor(js.JsonSaveable):
+ """
+ Handles the donor
+ """
+
+ _name = js.String()
+ _donations = js.List()
+
+ def __init__(self, name, *donations):
+ self._name = name
+ self._donations = list(donations)
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def donations(self):
+ return self._donations
+
+ def add_donation(self, donation):
+ self._donations.append(donation)
+
+ @property
+ def total_donations(self):
+ return sum(self._donations)
+ # return reduce(lambda a, x: a+x, self._donations, 0)
+ # s = 0
+ # for d in donations:
+ # s += d
+ # return s
+
+ @property
+ def count_donations(self):
+ return len(self._donations)
+
+ @property
+ def average_donation(self):
+ return self.total_donations / self.count_donations
+
+ @property
+ def letter(self):
+ """
+ Takes the donor iterable and returns a string that is a formatted thank you note
+ with the donor's name and last donation amount.
+ """
+ return "Dear {:s},\n\nWe greatly appreciate your generous donation of ${:,.2f}.\n\nThank you,\nThe Team".format(self._name, self._donations[-1])
+
+ @property
+ def filename(self):
+ 'Return a txt file name based on the donor name and using underscores instead of spaces'
+ return self._name.replace(' ', '_') + '.txt'
+
+ # allow other items to call the class
+ def __repr__(self):
+ return "{}: {}".format(self._name, self._donations)
+
+class DonorDB(js.JsonSaveable):
+ """
+ Handles collection of donors
+ """
+
+ _donors = js.Dict()
+
+ def __init__(self):
+ self._donors = {}
+
+ def add_donor(self, donor):
+ if donor.name.lower() in self._donors:
+ self._donors[donor.name.lower()].add_donation(*(donor.donations))
+ else:
+ self._donors[donor.name.lower()] = donor
+
+ def get_total_from_donor(self, donor_name):
+ return self._donors[donor_name.lower()].total_donations
+
+ def get_donor(self, donor_name):
+ try:
+ return self._donors[donor_name.lower()]
+ except KeyError:
+ print('Donor does not exist in the database')
+
+ # def export(self):
+ # return {donor.name:donor.donations for donor in self._donors.values()}
+
+ def donor_list(self):
+ name_list = [donor.name for donor in self._donors.values()]
+ return '\n'.join(name_list)
+
+ def letters_to_disk(self):
+ """
+ Generate one letter for each donor and write to disk
+ """
+ for donor in self._donors.values():
+ print('Generating letter to {:s}'.format(donor.name))
+ with open(donor.filename, 'w') as outfile:
+ outfile.write(donor.letter)
+ print()
+
+ def report(self):
+ sorted_donors = [donor for donor in self._donors.values()]
+ sorted_donors.sort(key=lambda donor: donor.total_donations, reverse=True)
+ report_rows = []
+ for d in sorted_donors:
+ report_rows.append('{:26s} {:>12s} {:^13d} {:>12s}'.format(d.name, '${:,.2f}'.format(d.total_donations), d.count_donations, '${:,.2f}'.format(d.average_donation)))
+ header = ('Donor Name | Total Given | Num Gifts | Average Gift\n') + ('-' * 66) + '\n'
+ return header + '\n'.join(report_rows) + '\n'
+
+ @property
+ def count_donors(self):
+ return len(self._donors)
+
+ @property
+ def count_donations(self):
+ return sum([len(donor.donations) for donor in self._donors.values()])
+
+ @property
+ def total_donations(self):
+ return sum([donor.total_donations for donor in self._donors.values()])
+
+ @property
+ def average_total_donation(self):
+ return self.total_donations / self.count_donors
+
+ @property
+ def average_single_donation(self):
+ return self.total_donations / self.count_donations
+
+ def __repr__(self):
+ return str([d for d in self._donors.values()])
+
+
+class Menu:
+ response = None
+
+ def __init__(self, title, menu):
+ self._title = title
+ self._menu = menu
+ error_msg = 'Not a valid response. Enter '
+ for key in self._menu:
+ error_msg += key + ', '
+ self._error = error_msg[:-3] + 'or ' + error_msg[-3] + '.\n'
+
+ def menu(self):
+ m = [str(k) + ') ' + str(v[0]) + '\n' for k, v in self._menu.items()]
+ return ''.join(m)
+
+ def get_response(self):
+ print(self._title)
+ print(self.menu())
+ response = input('>> ')
+ while response not in self._menu:
+ print(self._error)
+ response = input('>> ')
+ self.response = response
+
+ @property
+ def switch(self):
+ return {k:v[1] for k, v in self._menu.items()}
+
+def print_report():
+ print(donor_db.report())
+
+def return_to_main():
+ return
+
+def write_letters_to_disk():
+ """
+ Generate one letter for each donor and write to disk
+ """
+ donor_db.letters_to_disk()
+ return
+
+def enter_name(name, amount):
+ ex = 0
+ while ex == 0:
+ try:
+ amount = float(amount)
+ except ValueError:
+ print('Please enter a valid amount')
+ amount = input('>> ')
+ continue
+ else:
+ ex = 1
+ d = Donor(name, amount)
+ donor_db.add_donor(d)
+ print(d.letter)
+ print()
+
+def get_name_donation():
+ print('\nEnter the full name of the donor')
+ ty_name = input('>> ')
+ print('Enter a donation amount')
+ ty_amount = input('>> ')
+ print()
+ enter_name(ty_name, ty_amount)
+ return
+
+def print_donor_list():
+ print('\nDonors:')
+ print(donor_db.donor_list(), '\n')
+ pass
+
+def thank_you():
+ ty = Menu('Thank You Menu:', thank_you_menu)
+ ty.get_response()
+ ty.switch.get(ty.response)()
+ return
+
+def quit_program():
+ """
+ Save donor list to json file
+ """
+ with open('donor_db.json', 'w') as fp:
+ donor_db.to_json(fp)
+
+ sys.exit()
+
+main_menu = {
+ '1': ['Send a Thank You', thank_you]
+ , '2': ['Create a Report', print_report]
+ , '3': ['Send letters to everyone', write_letters_to_disk]
+ , '4': ['Quit', quit_program]
+ }
+
+thank_you_menu = {
+ '1': ['Enter a donor', get_name_donation]
+ , '2': ['See a list of donor names', print_donor_list]
+ , '3': ['Return to the Main Menu', return_to_main]
+ }
+
+def mainloop():
+ print('Welcome to Mailroom\n')
+ main = Menu('Main Menu:', main_menu)
+ while True:
+ main.get_response()
+ main.switch.get(main.response)()
+
+if __name__ == '__main__':
+ # Load existing database as a DonorDB object
+ with open('donor_db.json', 'r') as fp:
+ donor_db = DonorDB.from_json_file(fp)
+ mainloop()
diff --git a/Student/stephen/lesson04/test_mailroom_meta.py b/Student/stephen/lesson04/test_mailroom_meta.py
new file mode 100644
index 0000000..0726cf5
--- /dev/null
+++ b/Student/stephen/lesson04/test_mailroom_meta.py
@@ -0,0 +1,39 @@
+from mailroom_meta import Donor, DonorDB
+
+
+def test_donor_init():
+ d = Donor('William Gates III')
+ assert d.name == 'William Gates III'
+ assert d.donations == []
+ d.add_donation(10000)
+ d.add_donation(20000)
+ assert d.total_donations == 30000
+ #assert print(d) and False
+
+
+def test_donors():
+ d = Donor('Paul Allen')
+ d.add_donation(30000)
+
+ db = DonorDB()
+ db.add_donor(d)
+ assert db.get_total_from_donor('Paul Allen') == 30000
+
+ e = Donor('Jeff Bezos')
+ e.add_donation(40000)
+ e.add_donation(50000)
+
+ db.add_donor(e)
+
+ assert db.get_total_from_donor('Jeff Bezos') == 90000
+ assert db.count_donors == 2
+ assert db.count_donations == 3
+ assert db.total_donations == 120000
+ assert db.average_total_donation == 60000
+ assert db.average_single_donation == 40000
+
+ test_list = db.donor_list()
+ assert test_list.startswith('Paul Allen')
+ assert test_list.endswith('Jeff Bezos')
+
+ # assert print(db) and False
diff --git a/Student/stephen/lesson05/2018-06-24.log b/Student/stephen/lesson05/2018-06-24.log
new file mode 100644
index 0000000..b6551af
--- /dev/null
+++ b/Student/stephen/lesson05/2018-06-24.log
@@ -0,0 +1,12 @@
+2018-06-24 17:37:38,142 simple.py:35 WARNING The value of i is 50.
+2018-06-24 17:37:38,142 simple.py:39 ERROR Tried to divide by zero. Var i was 50. Recovered gracefully.
+2018-06-24 17:43:14,310 simple.py:35 WARNING The value of i is 50.
+2018-06-24 17:43:14,310 simple.py:39 ERROR Tried to divide by zero. Var i was 50. Recovered gracefully.
+2018-06-24 17:56:07,959 simple.py:35 WARNING The value of i is 50.
+2018-06-24 17:56:07,959 simple.py:39 ERROR Tried to divide by zero. Var i was 50. Recovered gracefully.
+2018-06-24 17:57:30,228 simple.py:36 WARNING The value of i is 50.
+2018-06-24 17:57:30,228 simple.py:40 ERROR Tried to divide by zero. Var i was 50. Recovered gracefully.
+2018-06-24 17:58:06,233 simple.py:36 WARNING The value of i is 50.
+2018-06-24 17:58:06,234 simple.py:40 ERROR Tried to divide by zero. Var i was 50. Recovered gracefully.
+2018-06-24 18:04:28,134 simple.py:35 WARNING The value of i is 50.
+2018-06-24 18:04:28,136 simple.py:39 ERROR Tried to divide by zero. Var i was 50. Recovered gracefully.
diff --git a/Student/stephen/lesson05/SOUKASENEDebugging.txt b/Student/stephen/lesson05/SOUKASENEDebugging.txt
new file mode 100644
index 0000000..63c14b0
--- /dev/null
+++ b/Student/stephen/lesson05/SOUKASENEDebugging.txt
@@ -0,0 +1,87 @@
+import sys
+
+
+def my_fun(n):
+ if n == 2:
+ return True
+ # to get the desired result need to include
+ # another termination case like below
+ elif n < 2:
+ return False
+
+ return my_fun(n/2)
+
+if __name__ == '__main__':
+ n = int(sys.argv[1])
+ print(my_fun(n))
+
+
+
+# results from debugging:
+# As we go deeper into the recursion using 15 as n
+# we see that n eventually just keeps dividing the results by 2
+# and never reaches an end. We need something to terminate the function
+# and return False once n goes below 2
+
+# $ python -m pdb recursive.py 15
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(1)()
+# -> import sys
+# (Pdb) n
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(4)()
+# -> def my_fun(n):
+# (Pdb) n
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(10)()
+# -> if __name__ == '__main__':
+# (Pdb) n
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(11)()
+# -> n = int(sys.argv[1])
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(12)()
+# -> print(my_fun(n))
+# (Pdb) s
+# --Call--
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(4)my_fun()
+# -> def my_fun(n):
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(5)my_fun()
+# -> if n == 2:
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(8)my_fun()
+# -> return my_fun(n/2)
+# (Pdb) pp n
+# 15
+# (Pdb) s
+# --Call--
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(4)my_fun()
+# -> def my_fun(n):
+# (Pdb) pp n
+# 7.5
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(5)my_fun()
+# -> if n == 2:
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(8)my_fun()
+# -> return my_fun(n/2)
+# (Pdb) pp n
+# 7.5
+# (Pdb) s
+# --Call--
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(4)my_fun()
+# -> def my_fun(n):
+# (Pdb) pp n
+# 3.75
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(5)my_fun()
+# -> if n == 2:
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(8)my_fun()
+# -> return my_fun(n/2)
+# (Pdb) s
+# --Call--
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(4)my_fun()
+# -> def my_fun(n):
+# (Pdb) pp n
+# 1.875
+# (Pdb)
+
+
diff --git a/Student/stephen/lesson05/lesson05_assignment.zip b/Student/stephen/lesson05/lesson05_assignment.zip
new file mode 100644
index 0000000..83d5650
Binary files /dev/null and b/Student/stephen/lesson05/lesson05_assignment.zip differ
diff --git a/Student/stephen/lesson05/pysyslog.py b/Student/stephen/lesson05/pysyslog.py
new file mode 100644
index 0000000..7b3de78
--- /dev/null
+++ b/Student/stephen/lesson05/pysyslog.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+
+## Tiny Syslog Server in Python.
+##
+## This is a tiny syslog server that is able to receive UDP based syslog
+## entries on a specified port and save them to a file.
+## That's it... it does nothing else...
+## There are a few configuration parameters.
+
+LOG_FILE = 'syslog.log'
+HOST = '0.0.0.0'
+TCP_PORT = 1514
+UDP_PORT = 514
+
+#
+# NO USER SERVICEABLE PARTS BELOW HERE...
+#
+
+import logging
+import time
+import threading
+import socketserver
+
+listening = False
+
+logging.basicConfig(level=logging.INFO, format='%(message)s', datefmt='', filename=LOG_FILE, filemode='a')
+
+class SyslogUDPHandler(socketserver.BaseRequestHandler):
+
+ def handle(self):
+ # data = bytes.decode(self.request[0].strip())
+ data = self.request[0].strip()
+ # socket = self.request[1]
+ print( "%s : " % self.client_address[0], str(data))
+ logging.info(str(data))
+
+class SyslogTCPHandler(socketserver.BaseRequestHandler):
+
+ End = '\n'
+ def join_data(self, total_data):
+ final_data = ''.join(total_data)
+ for data in final_data.split(self.End):
+ print( "%s : " % self.client_address[0], str(data))
+ logging.info(str(data))
+
+ def handle(self):
+ total_data = []
+ while listening:
+ data = self.request.recv(8192).strip()
+ if not data: break
+ if self.End in data:
+ split_index = data.rfind(self.End)
+ total_data.append(data[:split_index])
+ self.join_data(total_data)
+ del total_data[:]
+ total_data.append(data[split_index + 1:])
+ else:
+ total_data.append(data)
+ if len(total_data) > 0:
+ self.join_data(total_data)
+ # logging.info(str(data))
+
+if __name__ == "__main__":
+ listening = True
+ try:
+ # UDP server
+ udpServer = socketserver.UDPServer((HOST, UDP_PORT), SyslogUDPHandler)
+ udpThread = threading.Thread(target=udpServer.serve_forever)
+ udpThread.daemon = True
+ udpThread.start()
+ # udpServer.serve_forever(poll_interval=0.5)
+
+ # TCP server
+ tcpServer = socketserver.TCPServer((HOST, TCP_PORT), SyslogTCPHandler)
+ tcpThread = threading.Thread(target=tcpServer.serve_forever)
+ tcpThread.daemon = True
+ tcpThread.start()
+
+ while True:
+ time.sleep(1)
+ # tcpServer.serve_forever(poll_interval=0.5)
+ except (IOError, SystemExit):
+ raise
+ except KeyboardInterrupt:
+ listening = False
+ udpServer.shutdown()
+ udpServer.server_close()
+ tcpServer.shutdown()
+ tcpServer.server_close()
+ print ("Crtl+C Pressed. Shutting down.")
diff --git a/Student/stephen/lesson05/recursive.py b/Student/stephen/lesson05/recursive.py
new file mode 100644
index 0000000..63c14b0
--- /dev/null
+++ b/Student/stephen/lesson05/recursive.py
@@ -0,0 +1,87 @@
+import sys
+
+
+def my_fun(n):
+ if n == 2:
+ return True
+ # to get the desired result need to include
+ # another termination case like below
+ elif n < 2:
+ return False
+
+ return my_fun(n/2)
+
+if __name__ == '__main__':
+ n = int(sys.argv[1])
+ print(my_fun(n))
+
+
+
+# results from debugging:
+# As we go deeper into the recursion using 15 as n
+# we see that n eventually just keeps dividing the results by 2
+# and never reaches an end. We need something to terminate the function
+# and return False once n goes below 2
+
+# $ python -m pdb recursive.py 15
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(1)()
+# -> import sys
+# (Pdb) n
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(4)()
+# -> def my_fun(n):
+# (Pdb) n
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(10)()
+# -> if __name__ == '__main__':
+# (Pdb) n
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(11)()
+# -> n = int(sys.argv[1])
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(12)()
+# -> print(my_fun(n))
+# (Pdb) s
+# --Call--
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(4)my_fun()
+# -> def my_fun(n):
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(5)my_fun()
+# -> if n == 2:
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(8)my_fun()
+# -> return my_fun(n/2)
+# (Pdb) pp n
+# 15
+# (Pdb) s
+# --Call--
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(4)my_fun()
+# -> def my_fun(n):
+# (Pdb) pp n
+# 7.5
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(5)my_fun()
+# -> if n == 2:
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(8)my_fun()
+# -> return my_fun(n/2)
+# (Pdb) pp n
+# 7.5
+# (Pdb) s
+# --Call--
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(4)my_fun()
+# -> def my_fun(n):
+# (Pdb) pp n
+# 3.75
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(5)my_fun()
+# -> if n == 2:
+# (Pdb) s
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(8)my_fun()
+# -> return my_fun(n/2)
+# (Pdb) s
+# --Call--
+# > c:\users\ssouk\documents\python\python programming 220 ac\lesson05\recursive.py(4)my_fun()
+# -> def my_fun(n):
+# (Pdb) pp n
+# 1.875
+# (Pdb)
+
+
diff --git a/Student/stephen/lesson05/simple.py b/Student/stephen/lesson05/simple.py
new file mode 100644
index 0000000..bd08230
--- /dev/null
+++ b/Student/stephen/lesson05/simple.py
@@ -0,0 +1,49 @@
+#simple.py
+import logging
+from logging.handlers import SysLogHandler
+from datetime import date
+
+format = "%(asctime)s %(filename)s:%(lineno)-3d %(levelname)s %(message)s"
+format2 = "%(lineno)-3d %(levelname)s %(message)s"
+current_date = str(date.today())
+
+formatter = logging.Formatter(format)
+formatter2 = logging.Formatter(format2)
+
+file_handler = logging.FileHandler('{}.log'.format(current_date))
+file_handler.setLevel(logging.WARNING)
+file_handler.setFormatter(formatter)
+
+syslog_handler = SysLogHandler(address=("127.0.0.1", 514))
+syslog_handler.setLevel(logging.ERROR)
+syslog_handler.setFormatter(formatter2)
+
+console_handler = logging.StreamHandler()
+console_handler.setLevel(logging.DEBUG)
+console_handler.setFormatter(formatter)
+
+logger = logging.getLogger()
+logger.setLevel(logging.DEBUG)
+logger.addHandler(file_handler)
+logger.addHandler(syslog_handler)
+logger.addHandler(console_handler)
+
+def my_fun(n):
+ for i in range(0, n):
+ logging.debug(i)
+ if i == 50:
+ logging.warning("The value of i is 50.")
+ try:
+ i / (50 - i)
+ except ZeroDivisionError:
+ logging.error("Tried to divide by zero. Var i was {}. Recovered gracefully.".format(i))
+
+if __name__ == "__main__":
+ my_fun(100)
+
+
+# output for terminal running pysyslog.py:
+# $ python pysyslog.py
+# 127.0.0.1 : b'<11>39 ERROR Tried to divide by zero. Var i was 50. Recovered gr
+# acefully.\x00'
+
diff --git a/Student/stephen/lesson05/syslog.log b/Student/stephen/lesson05/syslog.log
new file mode 100644
index 0000000..2cc7453
--- /dev/null
+++ b/Student/stephen/lesson05/syslog.log
@@ -0,0 +1 @@
+b'<11>39 ERROR Tried to divide by zero. Var i was 50. Recovered gracefully.\x00'
diff --git a/Student/stephen/lesson06/calculator_activity/.coverage b/Student/stephen/lesson06/calculator_activity/.coverage
new file mode 100644
index 0000000..9941200
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/.coverage
@@ -0,0 +1 @@
+!coverage.py: This is a private format, don't read it directly!{"lines":{"C:\\Users\\ssouk\\Documents\\Python\\Python Programming 220 AC\\Lesson06\\calculator_activity\\calculator\\__init__.py":[1],"C:\\Users\\ssouk\\Documents\\Python\\Python Programming 220 AC\\Lesson06\\calculator_activity\\calculator\\adder.py":[3,6,9,10,15],"C:\\Users\\ssouk\\Documents\\Python\\Python Programming 220 AC\\Lesson06\\calculator_activity\\calculator\\subtracter.py":[3,6,9,10,15],"C:\\Users\\ssouk\\Documents\\Python\\Python Programming 220 AC\\Lesson06\\calculator_activity\\calculator\\multiplier.py":[3,6,9,10,15],"C:\\Users\\ssouk\\Documents\\Python\\Python Programming 220 AC\\Lesson06\\calculator_activity\\calculator\\divider.py":[3,6,9,10,15,16,19,17,18],"C:\\Users\\ssouk\\Documents\\Python\\Python Programming 220 AC\\Lesson06\\calculator_activity\\calculator\\calculator.py":[3,6,9,12,13,24,30,43,49,55,61,17,18,19,20,22,28,47,35,36,40,41,65,66,37,67,68,69,70,72,38,59,53],"C:\\Users\\ssouk\\Documents\\Python\\Python Programming 220 AC\\Lesson06\\calculator_activity\\calculator\\exceptions.py":[3,6,9,10]}}
\ No newline at end of file
diff --git a/Student/stephen/lesson06/calculator_activity/.pylintrc b/Student/stephen/lesson06/calculator_activity/.pylintrc
new file mode 100644
index 0000000..e1bf8fb
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/.pylintrc
@@ -0,0 +1,540 @@
+[MASTER]
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code
+extension-pkg-whitelist=
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Add files or directories matching the regex patterns to the blacklist. The
+# regex matches against base names, not paths.
+ignore-patterns=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Use multiple processes to speed up Pylint.
+jobs=1
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# Specify a configuration file.
+#rcfile=
+
+# When enabled, pylint would attempt to guess common misconfiguration and emit
+# user-friendly hints instead of false-positive error messages
+suggestion-mode=yes
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
+confidence=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+disable=print-statement,
+ parameter-unpacking,
+ unpacking-in-except,
+ old-raise-syntax,
+ backtick,
+ long-suffix,
+ old-ne-operator,
+ old-octal-literal,
+ import-star-module-level,
+ non-ascii-bytes-literal,
+ raw-checker-failed,
+ bad-inline-option,
+ locally-disabled,
+ locally-enabled,
+ file-ignored,
+ suppressed-message,
+ useless-suppression,
+ deprecated-pragma,
+ apply-builtin,
+ basestring-builtin,
+ buffer-builtin,
+ cmp-builtin,
+ coerce-builtin,
+ execfile-builtin,
+ file-builtin,
+ long-builtin,
+ raw_input-builtin,
+ reduce-builtin,
+ standarderror-builtin,
+ unicode-builtin,
+ xrange-builtin,
+ coerce-method,
+ delslice-method,
+ getslice-method,
+ setslice-method,
+ no-absolute-import,
+ old-division,
+ dict-iter-method,
+ dict-view-method,
+ next-method-called,
+ metaclass-assignment,
+ indexing-exception,
+ raising-string,
+ reload-builtin,
+ oct-method,
+ hex-method,
+ nonzero-method,
+ cmp-method,
+ input-builtin,
+ round-builtin,
+ intern-builtin,
+ unichr-builtin,
+ map-builtin-not-iterating,
+ zip-builtin-not-iterating,
+ range-builtin-not-iterating,
+ filter-builtin-not-iterating,
+ using-cmp-argument,
+ eq-without-hash,
+ div-method,
+ idiv-method,
+ rdiv-method,
+ exception-message-attribute,
+ invalid-str-codec,
+ sys-max-int,
+ bad-python3-import,
+ deprecated-string-function,
+ deprecated-str-translate-call,
+ deprecated-itertools-function,
+ deprecated-types-field,
+ next-method-defined,
+ dict-items-not-iterating,
+ dict-keys-not-iterating,
+ dict-values-not-iterating,
+ too-few-public-methods
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
+enable=c-extension-no-member
+
+
+[REPORTS]
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details
+#msg-template=
+
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio).You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Tells whether to display a full report or only the messages
+reports=yes
+
+# Activate the evaluation score.
+score=yes
+
+
+[REFACTORING]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+# Complete name of functions that never returns. When checking for
+# inconsistent-return-statements if a never returning function is called then
+# it will be considered as an explicit return statement and no message will be
+# printed.
+never-returning-functions=optparse.Values,sys.exit
+
+
+[BASIC]
+
+# Naming style matching correct argument names
+argument-naming-style=snake_case
+
+# Regular expression matching correct argument names. Overrides argument-
+# naming-style
+#argument-rgx=
+
+# Naming style matching correct attribute names
+attr-naming-style=snake_case
+
+# Regular expression matching correct attribute names. Overrides attr-naming-
+# style
+#attr-rgx=
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,
+ bar,
+ baz,
+ toto,
+ tutu,
+ tata
+
+# Naming style matching correct class attribute names
+class-attribute-naming-style=any
+
+# Regular expression matching correct class attribute names. Overrides class-
+# attribute-naming-style
+#class-attribute-rgx=
+
+# Naming style matching correct class names
+class-naming-style=PascalCase
+
+# Regular expression matching correct class names. Overrides class-naming-style
+#class-rgx=
+
+# Naming style matching correct constant names
+const-naming-style=UPPER_CASE
+
+# Regular expression matching correct constant names. Overrides const-naming-
+# style
+#const-rgx=
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+# Naming style matching correct function names
+function-naming-style=snake_case
+
+# Regular expression matching correct function names. Overrides function-
+# naming-style
+#function-rgx=
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,
+ j,
+ k,
+ ex,
+ Run,
+ _
+
+# Include a hint for the correct naming format with invalid-name
+include-naming-hint=no
+
+# Naming style matching correct inline iteration names
+inlinevar-naming-style=any
+
+# Regular expression matching correct inline iteration names. Overrides
+# inlinevar-naming-style
+#inlinevar-rgx=
+
+# Naming style matching correct method names
+method-naming-style=snake_case
+
+# Regular expression matching correct method names. Overrides method-naming-
+# style
+#method-rgx=
+
+# Naming style matching correct module names
+module-naming-style=snake_case
+
+# Regular expression matching correct module names. Overrides module-naming-
+# style
+#module-rgx=
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=^_
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+property-classes=abc.abstractproperty
+
+# Naming style matching correct variable names
+variable-naming-style=snake_case
+
+# Regular expression matching correct variable names. Overrides variable-
+# naming-style
+#variable-rgx=
+
+
+[FORMAT]
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )??$
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string=' '
+
+# Maximum number of characters on a single line.
+max-line-length=100
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# List of optional constructs for which whitespace checking is disabled. `dict-
+# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
+# `empty-line` allows space-only lines.
+no-space-check=trailing-comma,
+ dict-separator
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+single-line-class-stmt=no
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+
+[LOGGING]
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format
+logging-modules=logging
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,
+ XXX,
+ TODO
+
+
+[SIMILARITIES]
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+
+[SPELLING]
+
+# Limits count of emitted suggestions for spelling mistakes
+max-spelling-suggestions=4
+
+# Spelling dictionary name. Available dictionaries: none. To make it working
+# install python-enchant package.
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to indicated private dictionary in
+# --spelling-private-dict-file option instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference
+# can return multiple potential results while evaluating a Python object, but
+# some branches might not be evaluated, which results in partial inference. In
+# that case, it might be useful to still emit no-member and other checks for
+# the rest of the inferred objects.
+ignore-on-opaque-inference=yes
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis. It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# Show a hint with possible names when a member name was not found. The aspect
+# of finding the hint is based on edit distance.
+missing-member-hint=yes
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance=1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices=1
+
+
+[VARIABLES]
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables=yes
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,
+ _cb
+
+# A regular expression matching the name of dummy variables (i.e. expectedly
+# not used).
+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*|^ignored_|^unused_
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six.moves,past.builtins,future.builtins
+
+
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+ __new__,
+ setUp
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+ _fields,
+ _replace,
+ _source,
+ _make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Maximum number of boolean expressions in a if statement
+max-bool-expr=5
+
+# Maximum number of branch for function / method body
+max-branches=12
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+
+[IMPORTS]
+
+# Allow wildcard imports from modules that define __all__.
+allow-wildcard-with-all=no
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=optparse,tkinter.tix
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=Exception
diff --git a/Student/stephen/lesson06/calculator_activity/__pycache__/adder.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/__pycache__/adder.cpython-36.pyc
new file mode 100644
index 0000000..4675eda
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/__pycache__/adder.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/__pycache__/calculator.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/__pycache__/calculator.cpython-36.pyc
new file mode 100644
index 0000000..8c2a7ee
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/__pycache__/calculator.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/__pycache__/divider.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/__pycache__/divider.cpython-36.pyc
new file mode 100644
index 0000000..ed0a4c1
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/__pycache__/divider.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/__pycache__/exceptions.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/__pycache__/exceptions.cpython-36.pyc
new file mode 100644
index 0000000..54d36f4
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/__pycache__/exceptions.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/__pycache__/multiplier.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/__pycache__/multiplier.cpython-36.pyc
new file mode 100644
index 0000000..9c55882
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/__pycache__/multiplier.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/__pycache__/subtracter.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/__pycache__/subtracter.cpython-36.pyc
new file mode 100644
index 0000000..aff13c6
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/__pycache__/subtracter.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/__pycache__/test.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/__pycache__/test.cpython-36.pyc
new file mode 100644
index 0000000..fffdff2
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/__pycache__/test.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/__init__.py b/Student/stephen/lesson06/calculator_activity/calculator/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/__init__.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000..e9e0cdc
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/__init__.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/adder.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/adder.cpython-36.pyc
new file mode 100644
index 0000000..d728b10
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/adder.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/calculator.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/calculator.cpython-36.pyc
new file mode 100644
index 0000000..cc4d698
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/calculator.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/divider.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/divider.cpython-36.pyc
new file mode 100644
index 0000000..6a3d10a
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/divider.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/exceptions.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/exceptions.cpython-36.pyc
new file mode 100644
index 0000000..7b0039b
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/exceptions.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/multiplier.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/multiplier.cpython-36.pyc
new file mode 100644
index 0000000..a37c38c
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/multiplier.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/subtracter.cpython-36.pyc b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/subtracter.cpython-36.pyc
new file mode 100644
index 0000000..1ca0280
Binary files /dev/null and b/Student/stephen/lesson06/calculator_activity/calculator/__pycache__/subtracter.cpython-36.pyc differ
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/adder.py b/Student/stephen/lesson06/calculator_activity/calculator/adder.py
new file mode 100644
index 0000000..e37c532
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/calculator/adder.py
@@ -0,0 +1,15 @@
+"""
+This module provides the addition operation
+"""
+
+
+class Adder(object):
+ """
+ Class for addition
+ """
+ @staticmethod
+ def calc(operand_1, operand_2):
+ """
+ Method defining addition operation
+ """
+ return operand_1 + operand_2
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/calculator.py b/Student/stephen/lesson06/calculator_activity/calculator/calculator.py
new file mode 100644
index 0000000..b013ae7
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/calculator/calculator.py
@@ -0,0 +1,72 @@
+"""
+This module provides the Calculator class and methods
+"""
+
+
+from .exceptions import InsufficientOperands
+
+
+class Calculator(object):
+ """
+ Class defining the Calculator class of arithmatic operations
+ """
+ def __init__(self, adder, subtracter, multiplier, divider):
+ """
+ Initialize the class, creating operation attributes and stack attribute
+ """
+ self.adder = adder
+ self.subtracter = subtracter
+ self.multiplier = multiplier
+ self.divider = divider
+
+ self.stack = []
+
+ def enter_number(self, number):
+ """
+ Method for getting operands and inserting into stack
+ """
+ self.stack.insert(0, number)
+
+ def _do_calc(self, operator):
+ """
+ Return the result of the calculation, reversing order of the stack
+ to reflect order of operands in calculator methods
+ """
+ try:
+ result = operator.calc(self.stack[1], self.stack[0])
+ except IndexError:
+ raise InsufficientOperands
+
+ self.stack = [result]
+ return result
+
+ def add(self):
+ """
+ Addition calculation
+ """
+ return self._do_calc(self.adder)
+
+ def subtract(self):
+ """
+ Subtraction calculation
+ """
+ return self._do_calc(self.subtracter)
+
+ def multiply(self):
+ """
+ Multiplication calculation
+ """
+ return self._do_calc(self.multiplier)
+
+ def divide(self):
+ """
+ Division calculation
+ """
+ try:
+ result = self._do_calc(self.divider)
+ except ZeroDivisionError:
+ self.stack = self.stack[1:]
+ print('Cannot divide by zero. Try another number.')
+ raise
+ else:
+ return result
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/divider.py b/Student/stephen/lesson06/calculator_activity/calculator/divider.py
new file mode 100644
index 0000000..e3ddfd4
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/calculator/divider.py
@@ -0,0 +1,19 @@
+"""
+This module provides the division operation
+"""
+
+
+class Divider(object):
+ """
+ Class for division
+ """
+ @staticmethod
+ def calc(operand_1, operand_2):
+ """
+ This method defines the division operation
+ """
+ try:
+ operand_1 / operand_2
+ except ZeroDivisionError:
+ raise
+ return operand_1 / operand_2
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/exceptions.py b/Student/stephen/lesson06/calculator_activity/calculator/exceptions.py
new file mode 100644
index 0000000..90dc71e
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/calculator/exceptions.py
@@ -0,0 +1,10 @@
+"""
+This module provides custom exceptions
+"""
+
+
+class InsufficientOperands(Exception):
+ """
+ Provides a custom exception for entering too few operands
+ """
+ pass
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/multiplier.py b/Student/stephen/lesson06/calculator_activity/calculator/multiplier.py
new file mode 100644
index 0000000..b0cc361
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/calculator/multiplier.py
@@ -0,0 +1,15 @@
+"""
+This module provides the multiplication operation
+"""
+
+
+class Multiplier(object):
+ """
+ Class for multiplication
+ """
+ @staticmethod
+ def calc(operand_1, operand_2):
+ """
+ Method that defines the multiplication operation
+ """
+ return operand_1 * operand_2
diff --git a/Student/stephen/lesson06/calculator_activity/calculator/subtracter.py b/Student/stephen/lesson06/calculator_activity/calculator/subtracter.py
new file mode 100644
index 0000000..1c95c6b
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/calculator/subtracter.py
@@ -0,0 +1,15 @@
+"""
+This module provides the subtraction operation
+"""
+
+
+class Subtracter(object):
+ """
+ Class for subtraction
+ """
+ @staticmethod
+ def calc(operand_1, operand_2):
+ """
+ Method defining subtraction operation
+ """
+ return operand_1 - operand_2
diff --git a/Student/stephen/lesson06/calculator_activity/coverage_output.txt b/Student/stephen/lesson06/calculator_activity/coverage_output.txt
new file mode 100644
index 0000000..5d2b063
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/coverage_output.txt
@@ -0,0 +1,22 @@
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/calculator_activity
+$ coverage run --source=calculator -m unittest test.AdderTests test.SubtracterTests test.MultiplierTests test.DividerTests test.CalculatorTests
+..........
+----------------------------------------------------------------------
+Ran 10 tests in 0.010s
+
+OK
+Cannot divide by zero. Try another number.
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/calculator_activity
+$ coverage report
+Name Stmts Miss Cover
+----------------------------------------------
+calculator\__init__.py 0 0 100%
+calculator\adder.py 3 0 100%
+calculator\calculator.py 31 0 100%
+calculator\divider.py 7 0 100%
+calculator\exceptions.py 2 0 100%
+calculator\multiplier.py 3 0 100%
+calculator\subtracter.py 3 0 100%
+----------------------------------------------
+TOTAL 49 0 100%
diff --git a/Student/stephen/lesson06/calculator_activity/flake8_output.txt b/Student/stephen/lesson06/calculator_activity/flake8_output.txt
new file mode 100644
index 0000000..83b4352
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/flake8_output.txt
@@ -0,0 +1,41 @@
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/calculator_activity
+$ flake8 calculator
+calculator\calculator.py:5:45: E261 at least two spaces before inline comment
+calculator\calculator.py:5:46: E262 inline comment should start with '# '
+calculator\calculator.py:7:1: E302 expected 2 blank lines, found 1
+calculator\divider.py:5:1: E302 expected 2 blank lines, found 1
+calculator\exceptions.py:5:1: E302 expected 2 blank lines, found 1
+calculator\multiplier.py:5:1: E302 expected 2 blank lines, found 1
+calculator\subtracter.py:5:1: E302 expected 2 blank lines, found 1
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/calculator_activity
+$ flake8 calculator
+calculator\calculator.py:8:1: E302 expected 2 blank lines, found 1
+calculator\divider.py:5:1: E302 expected 2 blank lines, found 1
+calculator\exceptions.py:5:1: E302 expected 2 blank lines, found 1
+calculator\exceptions.py:10:1: W391 blank line at end of file
+calculator\multiplier.py:5:1: E302 expected 2 blank lines, found 1
+calculator\subtracter.py:5:1: E302 expected 2 blank lines, found 1
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/calculator_activity
+$ flake8 calculator
+calculator\divider.py:5:1: E302 expected 2 blank lines, found 1
+calculator\exceptions.py:5:1: E302 expected 2 blank lines, found 1
+calculator\exceptions.py:10:1: W391 blank line at end of file
+calculator\multiplier.py:5:1: E302 expected 2 blank lines, found 1
+calculator\subtracter.py:5:1: E302 expected 2 blank lines, found 1
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/calculator_activity
+$ flake8 calculator
+calculator\exceptions.py:11:1: W391 blank line at end of file
+calculator\multiplier.py:5:1: E302 expected 2 blank lines, found 1
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/calculator_activity
+$ flake8 calculator
+calculator\multiplier.py:5:1: E302 expected 2 blank lines, found 1
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/calculator_activity
+$ flake8 calculator
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/calculator_activity
+$
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/calculator___init___py.html b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator___init___py.html
new file mode 100644
index 0000000..7a754ab
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator___init___py.html
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+ Coverage for calculator\__init__.py: 100%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ r
+ m
+ x
+ p toggle line displays
+
+
+ j
+ k next/prev highlighted chunk
+
+
+ 0 (zero) top of page
+
+
+ 1 (one) first highlighted chunk
+
+
+
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_adder_py.html b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_adder_py.html
new file mode 100644
index 0000000..a790a72
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_adder_py.html
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+ Coverage for calculator\adder.py: 100%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ r
+ m
+ x
+ p toggle line displays
+
+
+ j
+ k next/prev highlighted chunk
+
+
+ 0 (zero) top of page
+
+
+ 1 (one) first highlighted chunk
+
+
+
+
+
+
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+
+
+
+"""
+This module provides the addition operation
+"""
+
+
+class Adder ( object ) :
+ """
+ Class for addition
+ """
+ @ staticmethod
+ def calc ( operand_1 , operand_2 ) :
+ """
+ Method defining addition operation
+ """
+ return operand_1 + operand_2
+
+
+
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_calculator_py.html b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_calculator_py.html
new file mode 100644
index 0000000..a78d941
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_calculator_py.html
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
+
+ Coverage for calculator\calculator.py: 100%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ r
+ m
+ x
+ p toggle line displays
+
+
+ j
+ k next/prev highlighted chunk
+
+
+ 0 (zero) top of page
+
+
+ 1 (one) first highlighted chunk
+
+
+
+
+
+
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+
+
+
+"""
+This module provides the Calculator class and methods
+"""
+
+
+from . exceptions import InsufficientOperands
+
+
+class Calculator ( object ) :
+ """
+ Class defining the Calculator class of arithmatic operations
+ """
+ def __init__ ( self , adder , subtracter , multiplier , divider ) :
+ """
+ Initialize the class, creating operation attributes and stack attribute
+ """
+ self . adder = adder
+ self . subtracter = subtracter
+ self . multiplier = multiplier
+ self . divider = divider
+
+ self . stack = [ ]
+
+ def enter_number ( self , number ) :
+ """
+ Method for getting operands and inserting into stack
+ """
+ self . stack . insert ( 0 , number )
+
+ def _do_calc ( self , operator ) :
+ """
+ Return the result of the calculation, reversing order of the stack
+ to reflect order of operands in calculator methods
+ """
+ try :
+ result = operator . calc ( self . stack [ 1 ] , self . stack [ 0 ] )
+ except IndexError :
+ raise InsufficientOperands
+
+ self . stack = [ result ]
+ return result
+
+ def add ( self ) :
+ """
+ Addition calculation
+ """
+ return self . _do_calc ( self . adder )
+
+ def subtract ( self ) :
+ """
+ Subtraction calculation
+ """
+ return self . _do_calc ( self . subtracter )
+
+ def multiply ( self ) :
+ """
+ Multiplication calculation
+ """
+ return self . _do_calc ( self . multiplier )
+
+ def divide ( self ) :
+ """
+ Division calculation
+ """
+ try :
+ result = self . _do_calc ( self . divider )
+ except ZeroDivisionError :
+ self . stack = self . stack [ 1 : ]
+ print ( 'Cannot divide by zero. Try another number.' )
+ raise
+ else :
+ return result
+
+
+
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_divider_py.html b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_divider_py.html
new file mode 100644
index 0000000..4474a4c
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_divider_py.html
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+ Coverage for calculator\divider.py: 100%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ r
+ m
+ x
+ p toggle line displays
+
+
+ j
+ k next/prev highlighted chunk
+
+
+ 0 (zero) top of page
+
+
+ 1 (one) first highlighted chunk
+
+
+
+
+
+
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+
+
+
+"""
+This module provides the division operation
+"""
+
+
+class Divider ( object ) :
+ """
+ Class for division
+ """
+ @ staticmethod
+ def calc ( operand_1 , operand_2 ) :
+ """
+ This method defines the division operation
+ """
+ try :
+ operand_1 / operand_2
+ except ZeroDivisionError :
+ raise
+ return operand_1 / operand_2
+
+
+
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_exceptions_py.html b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_exceptions_py.html
new file mode 100644
index 0000000..24d596c
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_exceptions_py.html
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+ Coverage for calculator\exceptions.py: 100%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ r
+ m
+ x
+ p toggle line displays
+
+
+ j
+ k next/prev highlighted chunk
+
+
+ 0 (zero) top of page
+
+
+ 1 (one) first highlighted chunk
+
+
+
+
+
+
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+
+
+
+"""
+This module provides custom exceptions
+"""
+
+
+class InsufficientOperands ( Exception ) :
+ """
+ Provides a custom exception for entering too few operands
+ """
+ pass
+
+
+
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_multiplier_py.html b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_multiplier_py.html
new file mode 100644
index 0000000..8a65e8d
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_multiplier_py.html
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+ Coverage for calculator\multiplier.py: 100%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ r
+ m
+ x
+ p toggle line displays
+
+
+ j
+ k next/prev highlighted chunk
+
+
+ 0 (zero) top of page
+
+
+ 1 (one) first highlighted chunk
+
+
+
+
+
+
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+
+
+
+"""
+This module provides the multiplication operation
+"""
+
+
+class Multiplier ( object ) :
+ """
+ Class for multiplication
+ """
+ @ staticmethod
+ def calc ( operand_1 , operand_2 ) :
+ """
+ Method that defines the multiplication operation
+ """
+ return operand_1 * operand_2
+
+
+
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_subtracter_py.html b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_subtracter_py.html
new file mode 100644
index 0000000..fa8be00
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/calculator_subtracter_py.html
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+ Coverage for calculator\subtracter.py: 100%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ r
+ m
+ x
+ p toggle line displays
+
+
+ j
+ k next/prev highlighted chunk
+
+
+ 0 (zero) top of page
+
+
+ 1 (one) first highlighted chunk
+
+
+
+
+
+
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+
+
+
+"""
+This module provides the subtraction operation
+"""
+
+
+class Subtracter ( object ) :
+ """
+ Class for subtraction
+ """
+ @ staticmethod
+ def calc ( operand_1 , operand_2 ) :
+ """
+ Method defining subtraction operation
+ """
+ return operand_1 - operand_2
+
+
+
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/coverage_html.js b/Student/stephen/lesson06/calculator_activity/htmlcov/coverage_html.js
new file mode 100644
index 0000000..f6f5de2
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/coverage_html.js
@@ -0,0 +1,584 @@
+// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+// For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+// Coverage.py HTML report browser code.
+/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */
+/*global coverage: true, document, window, $ */
+
+coverage = {};
+
+// Find all the elements with shortkey_* class, and use them to assign a shortcut key.
+coverage.assign_shortkeys = function () {
+ $("*[class*='shortkey_']").each(function (i, e) {
+ $.each($(e).attr("class").split(" "), function (i, c) {
+ if (/^shortkey_/.test(c)) {
+ $(document).bind('keydown', c.substr(9), function () {
+ $(e).click();
+ });
+ }
+ });
+ });
+};
+
+// Create the events for the help panel.
+coverage.wire_up_help_panel = function () {
+ $("#keyboard_icon").click(function () {
+ // Show the help panel, and position it so the keyboard icon in the
+ // panel is in the same place as the keyboard icon in the header.
+ $(".help_panel").show();
+ var koff = $("#keyboard_icon").offset();
+ var poff = $("#panel_icon").position();
+ $(".help_panel").offset({
+ top: koff.top-poff.top,
+ left: koff.left-poff.left
+ });
+ });
+ $("#panel_icon").click(function () {
+ $(".help_panel").hide();
+ });
+};
+
+// Create the events for the filter box.
+coverage.wire_up_filter = function () {
+ // Cache elements.
+ var table = $("table.index");
+ var table_rows = table.find("tbody tr");
+ var table_row_names = table_rows.find("td.name a");
+ var no_rows = $("#no_rows");
+
+ // Create a duplicate table footer that we can modify with dynamic summed values.
+ var table_footer = $("table.index tfoot tr");
+ var table_dynamic_footer = table_footer.clone();
+ table_dynamic_footer.attr('class', 'total_dynamic hidden');
+ table_footer.after(table_dynamic_footer);
+
+ // Observe filter keyevents.
+ $("#filter").on("keyup change", $.debounce(150, function (event) {
+ var filter_value = $(this).val();
+
+ if (filter_value === "") {
+ // Filter box is empty, remove all filtering.
+ table_rows.removeClass("hidden");
+
+ // Show standard footer, hide dynamic footer.
+ table_footer.removeClass("hidden");
+ table_dynamic_footer.addClass("hidden");
+
+ // Hide placeholder, show table.
+ if (no_rows.length > 0) {
+ no_rows.hide();
+ }
+ table.show();
+
+ }
+ else {
+ // Filter table items by value.
+ var hidden = 0;
+ var shown = 0;
+
+ // Hide / show elements.
+ $.each(table_row_names, function () {
+ var element = $(this).parents("tr");
+
+ if ($(this).text().indexOf(filter_value) === -1) {
+ // hide
+ element.addClass("hidden");
+ hidden++;
+ }
+ else {
+ // show
+ element.removeClass("hidden");
+ shown++;
+ }
+ });
+
+ // Show placeholder if no rows will be displayed.
+ if (no_rows.length > 0) {
+ if (shown === 0) {
+ // Show placeholder, hide table.
+ no_rows.show();
+ table.hide();
+ }
+ else {
+ // Hide placeholder, show table.
+ no_rows.hide();
+ table.show();
+ }
+ }
+
+ // Manage dynamic header:
+ if (hidden > 0) {
+ // Calculate new dynamic sum values based on visible rows.
+ for (var column = 2; column < 20; column++) {
+ // Calculate summed value.
+ var cells = table_rows.find('td:nth-child(' + column + ')');
+ if (!cells.length) {
+ // No more columns...!
+ break;
+ }
+
+ var sum = 0, numer = 0, denom = 0;
+ $.each(cells.filter(':visible'), function () {
+ var ratio = $(this).data("ratio");
+ if (ratio) {
+ var splitted = ratio.split(" ");
+ numer += parseInt(splitted[0], 10);
+ denom += parseInt(splitted[1], 10);
+ }
+ else {
+ sum += parseInt(this.innerHTML, 10);
+ }
+ });
+
+ // Get footer cell element.
+ var footer_cell = table_dynamic_footer.find('td:nth-child(' + column + ')');
+
+ // Set value into dynamic footer cell element.
+ if (cells[0].innerHTML.indexOf('%') > -1) {
+ // Percentage columns use the numerator and denominator,
+ // and adapt to the number of decimal places.
+ var match = /\.([0-9]+)/.exec(cells[0].innerHTML);
+ var places = 0;
+ if (match) {
+ places = match[1].length;
+ }
+ var pct = numer * 100 / denom;
+ footer_cell.text(pct.toFixed(places) + '%');
+ }
+ else {
+ footer_cell.text(sum);
+ }
+ }
+
+ // Hide standard footer, show dynamic footer.
+ table_footer.addClass("hidden");
+ table_dynamic_footer.removeClass("hidden");
+ }
+ else {
+ // Show standard footer, hide dynamic footer.
+ table_footer.removeClass("hidden");
+ table_dynamic_footer.addClass("hidden");
+ }
+ }
+ }));
+
+ // Trigger change event on setup, to force filter on page refresh
+ // (filter value may still be present).
+ $("#filter").trigger("change");
+};
+
+// Loaded on index.html
+coverage.index_ready = function ($) {
+ // Look for a cookie containing previous sort settings:
+ var sort_list = [];
+ var cookie_name = "COVERAGE_INDEX_SORT";
+ var i;
+
+ // This almost makes it worth installing the jQuery cookie plugin:
+ if (document.cookie.indexOf(cookie_name) > -1) {
+ var cookies = document.cookie.split(";");
+ for (i = 0; i < cookies.length; i++) {
+ var parts = cookies[i].split("=");
+
+ if ($.trim(parts[0]) === cookie_name && parts[1]) {
+ sort_list = eval("[[" + parts[1] + "]]");
+ break;
+ }
+ }
+ }
+
+ // Create a new widget which exists only to save and restore
+ // the sort order:
+ $.tablesorter.addWidget({
+ id: "persistentSort",
+
+ // Format is called by the widget before displaying:
+ format: function (table) {
+ if (table.config.sortList.length === 0 && sort_list.length > 0) {
+ // This table hasn't been sorted before - we'll use
+ // our stored settings:
+ $(table).trigger('sorton', [sort_list]);
+ }
+ else {
+ // This is not the first load - something has
+ // already defined sorting so we'll just update
+ // our stored value to match:
+ sort_list = table.config.sortList;
+ }
+ }
+ });
+
+ // Configure our tablesorter to handle the variable number of
+ // columns produced depending on report options:
+ var headers = [];
+ var col_count = $("table.index > thead > tr > th").length;
+
+ headers[0] = { sorter: 'text' };
+ for (i = 1; i < col_count-1; i++) {
+ headers[i] = { sorter: 'digit' };
+ }
+ headers[col_count-1] = { sorter: 'percent' };
+
+ // Enable the table sorter:
+ $("table.index").tablesorter({
+ widgets: ['persistentSort'],
+ headers: headers
+ });
+
+ coverage.assign_shortkeys();
+ coverage.wire_up_help_panel();
+ coverage.wire_up_filter();
+
+ // Watch for page unload events so we can save the final sort settings:
+ $(window).unload(function () {
+ document.cookie = cookie_name + "=" + sort_list.toString() + "; path=/";
+ });
+};
+
+// -- pyfile stuff --
+
+coverage.pyfile_ready = function ($) {
+ // If we're directed to a particular line number, highlight the line.
+ var frag = location.hash;
+ if (frag.length > 2 && frag[1] === 'n') {
+ $(frag).addClass('highlight');
+ coverage.set_sel(parseInt(frag.substr(2), 10));
+ }
+ else {
+ coverage.set_sel(0);
+ }
+
+ $(document)
+ .bind('keydown', 'j', coverage.to_next_chunk_nicely)
+ .bind('keydown', 'k', coverage.to_prev_chunk_nicely)
+ .bind('keydown', '0', coverage.to_top)
+ .bind('keydown', '1', coverage.to_first_chunk)
+ ;
+
+ $(".button_toggle_run").click(function (evt) {coverage.toggle_lines(evt.target, "run");});
+ $(".button_toggle_exc").click(function (evt) {coverage.toggle_lines(evt.target, "exc");});
+ $(".button_toggle_mis").click(function (evt) {coverage.toggle_lines(evt.target, "mis");});
+ $(".button_toggle_par").click(function (evt) {coverage.toggle_lines(evt.target, "par");});
+
+ coverage.assign_shortkeys();
+ coverage.wire_up_help_panel();
+
+ coverage.init_scroll_markers();
+
+ // Rebuild scroll markers after window high changing
+ $(window).resize(coverage.resize_scroll_markers);
+};
+
+coverage.toggle_lines = function (btn, cls) {
+ btn = $(btn);
+ var hide = "hide_"+cls;
+ if (btn.hasClass(hide)) {
+ $("#source ."+cls).removeClass(hide);
+ btn.removeClass(hide);
+ }
+ else {
+ $("#source ."+cls).addClass(hide);
+ btn.addClass(hide);
+ }
+};
+
+// Return the nth line div.
+coverage.line_elt = function (n) {
+ return $("#t" + n);
+};
+
+// Return the nth line number div.
+coverage.num_elt = function (n) {
+ return $("#n" + n);
+};
+
+// Return the container of all the code.
+coverage.code_container = function () {
+ return $(".linenos");
+};
+
+// Set the selection. b and e are line numbers.
+coverage.set_sel = function (b, e) {
+ // The first line selected.
+ coverage.sel_begin = b;
+ // The next line not selected.
+ coverage.sel_end = (e === undefined) ? b+1 : e;
+};
+
+coverage.to_top = function () {
+ coverage.set_sel(0, 1);
+ coverage.scroll_window(0);
+};
+
+coverage.to_first_chunk = function () {
+ coverage.set_sel(0, 1);
+ coverage.to_next_chunk();
+};
+
+coverage.is_transparent = function (color) {
+ // Different browsers return different colors for "none".
+ return color === "transparent" || color === "rgba(0, 0, 0, 0)";
+};
+
+coverage.to_next_chunk = function () {
+ var c = coverage;
+
+ // Find the start of the next colored chunk.
+ var probe = c.sel_end;
+ var color, probe_line;
+ while (true) {
+ probe_line = c.line_elt(probe);
+ if (probe_line.length === 0) {
+ return;
+ }
+ color = probe_line.css("background-color");
+ if (!c.is_transparent(color)) {
+ break;
+ }
+ probe++;
+ }
+
+ // There's a next chunk, `probe` points to it.
+ var begin = probe;
+
+ // Find the end of this chunk.
+ var next_color = color;
+ while (next_color === color) {
+ probe++;
+ probe_line = c.line_elt(probe);
+ next_color = probe_line.css("background-color");
+ }
+ c.set_sel(begin, probe);
+ c.show_selection();
+};
+
+coverage.to_prev_chunk = function () {
+ var c = coverage;
+
+ // Find the end of the prev colored chunk.
+ var probe = c.sel_begin-1;
+ var probe_line = c.line_elt(probe);
+ if (probe_line.length === 0) {
+ return;
+ }
+ var color = probe_line.css("background-color");
+ while (probe > 0 && c.is_transparent(color)) {
+ probe--;
+ probe_line = c.line_elt(probe);
+ if (probe_line.length === 0) {
+ return;
+ }
+ color = probe_line.css("background-color");
+ }
+
+ // There's a prev chunk, `probe` points to its last line.
+ var end = probe+1;
+
+ // Find the beginning of this chunk.
+ var prev_color = color;
+ while (prev_color === color) {
+ probe--;
+ probe_line = c.line_elt(probe);
+ prev_color = probe_line.css("background-color");
+ }
+ c.set_sel(probe+1, end);
+ c.show_selection();
+};
+
+// Return the line number of the line nearest pixel position pos
+coverage.line_at_pos = function (pos) {
+ var l1 = coverage.line_elt(1),
+ l2 = coverage.line_elt(2),
+ result;
+ if (l1.length && l2.length) {
+ var l1_top = l1.offset().top,
+ line_height = l2.offset().top - l1_top,
+ nlines = (pos - l1_top) / line_height;
+ if (nlines < 1) {
+ result = 1;
+ }
+ else {
+ result = Math.ceil(nlines);
+ }
+ }
+ else {
+ result = 1;
+ }
+ return result;
+};
+
+// Returns 0, 1, or 2: how many of the two ends of the selection are on
+// the screen right now?
+coverage.selection_ends_on_screen = function () {
+ if (coverage.sel_begin === 0) {
+ return 0;
+ }
+
+ var top = coverage.line_elt(coverage.sel_begin);
+ var next = coverage.line_elt(coverage.sel_end-1);
+
+ return (
+ (top.isOnScreen() ? 1 : 0) +
+ (next.isOnScreen() ? 1 : 0)
+ );
+};
+
+coverage.to_next_chunk_nicely = function () {
+ coverage.finish_scrolling();
+ if (coverage.selection_ends_on_screen() === 0) {
+ // The selection is entirely off the screen: select the top line on
+ // the screen.
+ var win = $(window);
+ coverage.select_line_or_chunk(coverage.line_at_pos(win.scrollTop()));
+ }
+ coverage.to_next_chunk();
+};
+
+coverage.to_prev_chunk_nicely = function () {
+ coverage.finish_scrolling();
+ if (coverage.selection_ends_on_screen() === 0) {
+ var win = $(window);
+ coverage.select_line_or_chunk(coverage.line_at_pos(win.scrollTop() + win.height()));
+ }
+ coverage.to_prev_chunk();
+};
+
+// Select line number lineno, or if it is in a colored chunk, select the
+// entire chunk
+coverage.select_line_or_chunk = function (lineno) {
+ var c = coverage;
+ var probe_line = c.line_elt(lineno);
+ if (probe_line.length === 0) {
+ return;
+ }
+ var the_color = probe_line.css("background-color");
+ if (!c.is_transparent(the_color)) {
+ // The line is in a highlighted chunk.
+ // Search backward for the first line.
+ var probe = lineno;
+ var color = the_color;
+ while (probe > 0 && color === the_color) {
+ probe--;
+ probe_line = c.line_elt(probe);
+ if (probe_line.length === 0) {
+ break;
+ }
+ color = probe_line.css("background-color");
+ }
+ var begin = probe + 1;
+
+ // Search forward for the last line.
+ probe = lineno;
+ color = the_color;
+ while (color === the_color) {
+ probe++;
+ probe_line = c.line_elt(probe);
+ color = probe_line.css("background-color");
+ }
+
+ coverage.set_sel(begin, probe);
+ }
+ else {
+ coverage.set_sel(lineno);
+ }
+};
+
+coverage.show_selection = function () {
+ var c = coverage;
+
+ // Highlight the lines in the chunk
+ c.code_container().find(".highlight").removeClass("highlight");
+ for (var probe = c.sel_begin; probe > 0 && probe < c.sel_end; probe++) {
+ c.num_elt(probe).addClass("highlight");
+ }
+
+ c.scroll_to_selection();
+};
+
+coverage.scroll_to_selection = function () {
+ // Scroll the page if the chunk isn't fully visible.
+ if (coverage.selection_ends_on_screen() < 2) {
+ // Need to move the page. The html,body trick makes it scroll in all
+ // browsers, got it from http://stackoverflow.com/questions/3042651
+ var top = coverage.line_elt(coverage.sel_begin);
+ var top_pos = parseInt(top.offset().top, 10);
+ coverage.scroll_window(top_pos - 30);
+ }
+};
+
+coverage.scroll_window = function (to_pos) {
+ $("html,body").animate({scrollTop: to_pos}, 200);
+};
+
+coverage.finish_scrolling = function () {
+ $("html,body").stop(true, true);
+};
+
+coverage.init_scroll_markers = function () {
+ var c = coverage;
+ // Init some variables
+ c.lines_len = $('td.text p').length;
+ c.body_h = $('body').height();
+ c.header_h = $('div#header').height();
+ c.missed_lines = $('td.text p.mis, td.text p.par');
+
+ // Build html
+ c.resize_scroll_markers();
+};
+
+coverage.resize_scroll_markers = function () {
+ var c = coverage,
+ min_line_height = 3,
+ max_line_height = 10,
+ visible_window_h = $(window).height();
+
+ $('#scroll_marker').remove();
+ // Don't build markers if the window has no scroll bar.
+ if (c.body_h <= visible_window_h) {
+ return;
+ }
+
+ $("body").append("
");
+ var scroll_marker = $('#scroll_marker'),
+ marker_scale = scroll_marker.height() / c.body_h,
+ line_height = scroll_marker.height() / c.lines_len;
+
+ // Line height must be between the extremes.
+ if (line_height > min_line_height) {
+ if (line_height > max_line_height) {
+ line_height = max_line_height;
+ }
+ }
+ else {
+ line_height = min_line_height;
+ }
+
+ var previous_line = -99,
+ last_mark,
+ last_top;
+
+ c.missed_lines.each(function () {
+ var line_top = Math.round($(this).offset().top * marker_scale),
+ id_name = $(this).attr('id'),
+ line_number = parseInt(id_name.substring(1, id_name.length));
+
+ if (line_number === previous_line + 1) {
+ // If this solid missed block just make previous mark higher.
+ last_mark.css({
+ 'height': line_top + line_height - last_top
+ });
+ }
+ else {
+ // Add colored line in scroll_marker block.
+ scroll_marker.append('
');
+ last_mark = $('#m' + line_number);
+ last_mark.css({
+ 'height': line_height,
+ 'top': line_top
+ });
+ last_top = line_top;
+ }
+
+ previous_line = line_number;
+ });
+};
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/index.html b/Student/stephen/lesson06/calculator_activity/htmlcov/index.html
new file mode 100644
index 0000000..2fb4acc
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/index.html
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
+ Coverage report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ n
+ s
+ m
+ x
+
+ c change column sorting
+
+
+
+
+
+
+
+
+ No items found using the specified filter.
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.ba-throttle-debounce.min.js b/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.ba-throttle-debounce.min.js
new file mode 100644
index 0000000..648fe5d
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.ba-throttle-debounce.min.js
@@ -0,0 +1,9 @@
+/*
+ * jQuery throttle / debounce - v1.1 - 3/7/2010
+ * http://benalman.com/projects/jquery-throttle-debounce-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.hotkeys.js b/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.hotkeys.js
new file mode 100644
index 0000000..09b21e0
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.hotkeys.js
@@ -0,0 +1,99 @@
+/*
+ * jQuery Hotkeys Plugin
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ *
+ * Based upon the plugin by Tzury Bar Yochay:
+ * http://github.com/tzuryby/hotkeys
+ *
+ * Original idea by:
+ * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
+*/
+
+(function(jQuery){
+
+ jQuery.hotkeys = {
+ version: "0.8",
+
+ specialKeys: {
+ 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
+ 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
+ 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
+ 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
+ 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
+ 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
+ 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
+ },
+
+ shiftNums: {
+ "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
+ "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
+ ".": ">", "/": "?", "\\": "|"
+ }
+ };
+
+ function keyHandler( handleObj ) {
+ // Only care when a possible input has been specified
+ if ( typeof handleObj.data !== "string" ) {
+ return;
+ }
+
+ var origHandler = handleObj.handler,
+ keys = handleObj.data.toLowerCase().split(" ");
+
+ handleObj.handler = function( event ) {
+ // Don't fire in text-accepting inputs that we didn't directly bind to
+ if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
+ event.target.type === "text") ) {
+ return;
+ }
+
+ // Keypress represents characters, not special keys
+ var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
+ character = String.fromCharCode( event.which ).toLowerCase(),
+ key, modif = "", possible = {};
+
+ // check combinations (alt|ctrl|shift+anything)
+ if ( event.altKey && special !== "alt" ) {
+ modif += "alt+";
+ }
+
+ if ( event.ctrlKey && special !== "ctrl" ) {
+ modif += "ctrl+";
+ }
+
+ // TODO: Need to make sure this works consistently across platforms
+ if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
+ modif += "meta+";
+ }
+
+ if ( event.shiftKey && special !== "shift" ) {
+ modif += "shift+";
+ }
+
+ if ( special ) {
+ possible[ modif + special ] = true;
+
+ } else {
+ possible[ modif + character ] = true;
+ possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
+
+ // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
+ if ( modif === "shift+" ) {
+ possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
+ }
+ }
+
+ for ( var i = 0, l = keys.length; i < l; i++ ) {
+ if ( possible[ keys[i] ] ) {
+ return origHandler.apply( this, arguments );
+ }
+ }
+ };
+ }
+
+ jQuery.each([ "keydown", "keyup", "keypress" ], function() {
+ jQuery.event.special[ this ] = { add: keyHandler };
+ });
+
+})( jQuery );
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.isonscreen.js b/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.isonscreen.js
new file mode 100644
index 0000000..0182ebd
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.isonscreen.js
@@ -0,0 +1,53 @@
+/* Copyright (c) 2010
+ * @author Laurence Wheway
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * @version 1.2.0
+ */
+(function($) {
+ jQuery.extend({
+ isOnScreen: function(box, container) {
+ //ensure numbers come in as intgers (not strings) and remove 'px' is it's there
+ for(var i in box){box[i] = parseFloat(box[i])};
+ for(var i in container){container[i] = parseFloat(container[i])};
+
+ if(!container){
+ container = {
+ left: $(window).scrollLeft(),
+ top: $(window).scrollTop(),
+ width: $(window).width(),
+ height: $(window).height()
+ }
+ }
+
+ if( box.left+box.width-container.left > 0 &&
+ box.left < container.width+container.left &&
+ box.top+box.height-container.top > 0 &&
+ box.top < container.height+container.top
+ ) return true;
+ return false;
+ }
+ })
+
+
+ jQuery.fn.isOnScreen = function (container) {
+ for(var i in container){container[i] = parseFloat(container[i])};
+
+ if(!container){
+ container = {
+ left: $(window).scrollLeft(),
+ top: $(window).scrollTop(),
+ width: $(window).width(),
+ height: $(window).height()
+ }
+ }
+
+ if( $(this).offset().left+$(this).width()-container.left > 0 &&
+ $(this).offset().left < container.width+container.left &&
+ $(this).offset().top+$(this).height()-container.top > 0 &&
+ $(this).offset().top < container.height+container.top
+ ) return true;
+ return false;
+ }
+})(jQuery);
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.min.js b/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.min.js
new file mode 100644
index 0000000..d1608e3
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML=" ",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML=" ","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML=" ",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
+if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" a ",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML=" ",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h ]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""," "],legend:[1,""," "],area:[1,""," "],param:[1,""," "],thead:[1,""],tr:[2,""],col:[2,""],td:[3,""],_default:k.htmlSerialize?[0,"",""]:[1,"X","
"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML=" a ",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")
+},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();ca ",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m});
\ No newline at end of file
diff --git a/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.tablesorter.min.js b/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.tablesorter.min.js
new file mode 100644
index 0000000..64c7007
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/htmlcov/jquery.tablesorter.min.js
@@ -0,0 +1,2 @@
+
+(function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i
1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($(' ').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;ib)?1:0));};function sortTextDesc(a,b){return((ba)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j 0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;ibody {
+ font-size: 16px;
+ }
+
+/* Set base font size to 12/16 */
+p {
+ font-size: .75em; /* 12/16 */
+ line-height: 1.33333333em; /* 16/12 */
+ }
+
+table {
+ border-collapse: collapse;
+ }
+td {
+ vertical-align: top;
+}
+table tr.hidden {
+ display: none !important;
+ }
+
+p#no_rows {
+ display: none;
+ font-size: 1.2em;
+ }
+
+a.nav {
+ text-decoration: none;
+ color: inherit;
+ }
+a.nav:hover {
+ text-decoration: underline;
+ color: inherit;
+ }
+
+/* Page structure */
+#header {
+ background: #f8f8f8;
+ width: 100%;
+ border-bottom: 1px solid #eee;
+ }
+
+#source {
+ padding: 1em;
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ }
+
+.indexfile #footer {
+ margin: 1em 3em;
+ }
+
+.pyfile #footer {
+ margin: 1em 1em;
+ }
+
+#footer .content {
+ padding: 0;
+ font-size: 85%;
+ font-family: verdana, sans-serif;
+ color: #666666;
+ font-style: italic;
+ }
+
+#index {
+ margin: 1em 0 0 3em;
+ }
+
+/* Header styles */
+#header .content {
+ padding: 1em 3em;
+ }
+
+h1 {
+ font-size: 1.25em;
+ display: inline-block;
+}
+
+#filter_container {
+ display: inline-block;
+ float: right;
+ margin: 0 2em 0 0;
+}
+#filter_container input {
+ width: 10em;
+}
+
+h2.stats {
+ margin-top: .5em;
+ font-size: 1em;
+}
+.stats span {
+ border: 1px solid;
+ padding: .1em .25em;
+ margin: 0 .1em;
+ cursor: pointer;
+ border-color: #999 #ccc #ccc #999;
+}
+.stats span.hide_run, .stats span.hide_exc,
+.stats span.hide_mis, .stats span.hide_par,
+.stats span.par.hide_run.hide_par {
+ border-color: #ccc #999 #999 #ccc;
+}
+.stats span.par.hide_run {
+ border-color: #999 #ccc #ccc #999;
+}
+
+.stats span.run {
+ background: #ddffdd;
+}
+.stats span.exc {
+ background: #eeeeee;
+}
+.stats span.mis {
+ background: #ffdddd;
+}
+.stats span.hide_run {
+ background: #eeffee;
+}
+.stats span.hide_exc {
+ background: #f5f5f5;
+}
+.stats span.hide_mis {
+ background: #ffeeee;
+}
+.stats span.par {
+ background: #ffffaa;
+}
+.stats span.hide_par {
+ background: #ffffcc;
+}
+
+/* Help panel */
+#keyboard_icon {
+ float: right;
+ margin: 5px;
+ cursor: pointer;
+}
+
+.help_panel {
+ position: absolute;
+ background: #ffffcc;
+ padding: .5em;
+ border: 1px solid #883;
+ display: none;
+}
+
+.indexfile .help_panel {
+ width: 20em; height: 4em;
+}
+
+.pyfile .help_panel {
+ width: 16em; height: 8em;
+}
+
+.help_panel .legend {
+ font-style: italic;
+ margin-bottom: 1em;
+}
+
+#panel_icon {
+ float: right;
+ cursor: pointer;
+}
+
+.keyhelp {
+ margin: .75em;
+}
+
+.keyhelp .key {
+ border: 1px solid black;
+ border-color: #888 #333 #333 #888;
+ padding: .1em .35em;
+ font-family: monospace;
+ font-weight: bold;
+ background: #eee;
+}
+
+/* Source file styles */
+.linenos p {
+ text-align: right;
+ margin: 0;
+ padding: 0 .5em;
+ color: #999999;
+ font-family: verdana, sans-serif;
+ font-size: .625em; /* 10/16 */
+ line-height: 1.6em; /* 16/10 */
+ }
+.linenos p.highlight {
+ background: #ffdd00;
+ }
+.linenos p a {
+ text-decoration: none;
+ color: #999999;
+ }
+.linenos p a:hover {
+ text-decoration: underline;
+ color: #999999;
+ }
+
+td.text {
+ width: 100%;
+ }
+.text p {
+ margin: 0;
+ padding: 0 0 0 .5em;
+ border-left: 2px solid #ffffff;
+ white-space: pre;
+ position: relative;
+ }
+
+.text p.mis {
+ background: #ffdddd;
+ border-left: 2px solid #ff0000;
+ }
+.text p.run, .text p.run.hide_par {
+ background: #ddffdd;
+ border-left: 2px solid #00ff00;
+ }
+.text p.exc {
+ background: #eeeeee;
+ border-left: 2px solid #808080;
+ }
+.text p.par, .text p.par.hide_run {
+ background: #ffffaa;
+ border-left: 2px solid #eeee99;
+ }
+.text p.hide_run, .text p.hide_exc, .text p.hide_mis, .text p.hide_par,
+.text p.hide_run.hide_par {
+ background: inherit;
+ }
+
+.text span.annotate {
+ font-family: georgia;
+ color: #666;
+ float: right;
+ padding-right: .5em;
+ }
+.text p.hide_par span.annotate {
+ display: none;
+ }
+.text span.annotate.long {
+ display: none;
+ }
+.text p:hover span.annotate.long {
+ display: block;
+ max-width: 50%;
+ white-space: normal;
+ float: right;
+ position: absolute;
+ top: 1.75em;
+ right: 1em;
+ width: 30em;
+ height: auto;
+ color: #333;
+ background: #ffffcc;
+ border: 1px solid #888;
+ padding: .25em .5em;
+ z-index: 999;
+ border-radius: .2em;
+ box-shadow: #cccccc .2em .2em .2em;
+ }
+
+/* Syntax coloring */
+.text .com {
+ color: green;
+ font-style: italic;
+ line-height: 1px;
+ }
+.text .key {
+ font-weight: bold;
+ line-height: 1px;
+ }
+.text .str {
+ color: #000080;
+ }
+
+/* index styles */
+#index td, #index th {
+ text-align: right;
+ width: 5em;
+ padding: .25em .5em;
+ border-bottom: 1px solid #eee;
+ }
+#index th {
+ font-style: italic;
+ color: #333;
+ border-bottom: 1px solid #ccc;
+ cursor: pointer;
+ }
+#index th:hover {
+ background: #eee;
+ border-bottom: 1px solid #999;
+ }
+#index td.left, #index th.left {
+ padding-left: 0;
+ }
+#index td.right, #index th.right {
+ padding-right: 0;
+ }
+#index th.headerSortDown, #index th.headerSortUp {
+ border-bottom: 1px solid #000;
+ white-space: nowrap;
+ background: #eee;
+ }
+#index th.headerSortDown:after {
+ content: " ↓";
+}
+#index th.headerSortUp:after {
+ content: " ↑";
+}
+#index td.name, #index th.name {
+ text-align: left;
+ width: auto;
+ }
+#index td.name a {
+ text-decoration: none;
+ color: #000;
+ }
+#index tr.total,
+#index tr.total_dynamic {
+ }
+#index tr.total td,
+#index tr.total_dynamic td {
+ font-weight: bold;
+ border-top: 1px solid #ccc;
+ border-bottom: none;
+ }
+#index tr.file:hover {
+ background: #eeeeee;
+ }
+#index tr.file:hover td.name {
+ text-decoration: underline;
+ color: #000;
+ }
+
+/* scroll marker styles */
+#scroll_marker {
+ position: fixed;
+ right: 0;
+ top: 0;
+ width: 16px;
+ height: 100%;
+ background: white;
+ border-left: 1px solid #eee;
+ }
+
+#scroll_marker .marker {
+ background: #eedddd;
+ position: absolute;
+ min-height: 3px;
+ width: 100%;
+ }
diff --git a/Student/stephen/lesson06/calculator_activity/load_calculator.py b/Student/stephen/lesson06/calculator_activity/load_calculator.py
new file mode 100644
index 0000000..bbba904
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/load_calculator.py
@@ -0,0 +1,4 @@
+import adder, subtracter, multiplier, divider
+from calculator import Calculator
+
+calculator = Calculator(adder.Adder(), subtracter.Subtracter(), multiplier.Multiplier(), divider.Divider())
diff --git a/Student/stephen/lesson06/calculator_activity/pylint_output.txt b/Student/stephen/lesson06/calculator_activity/pylint_output.txt
new file mode 100644
index 0000000..2dff432
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/pylint_output.txt
@@ -0,0 +1,80 @@
+Report
+======
+48 statements analysed.
+
+Statistics by type
+------------------
+
++---------+-------+-----------+-----------+------------+---------+
+|type |number |old number |difference |%documented |%badname |
++=========+=======+===========+===========+============+=========+
+|module |7 |7 |= |100.00 |0.00 |
++---------+-------+-----------+-----------+------------+---------+
+|class |6 |6 |= |100.00 |0.00 |
++---------+-------+-----------+-----------+------------+---------+
+|method |11 |11 |= |100.00 |0.00 |
++---------+-------+-----------+-----------+------------+---------+
+|function |0 |0 |= |0 |0 |
++---------+-------+-----------+-----------+------------+---------+
+
+
+
+External dependencies
+---------------------
+::
+
+ calculator
+ \-exceptions (calculator.calculator)
+
+
+
+Raw metrics
+-----------
+
++----------+-------+------+---------+-----------+
+|type |number |% |previous |difference |
++==========+=======+======+=========+===========+
+|code |66 |42.58 |NC |NC |
++----------+-------+------+---------+-----------+
+|docstring |70 |45.16 |NC |NC |
++----------+-------+------+---------+-----------+
+|comment |2 |1.29 |NC |NC |
++----------+-------+------+---------+-----------+
+|empty |17 |10.97 |NC |NC |
++----------+-------+------+---------+-----------+
+
+
+
+Duplication
+-----------
+
++-------------------------+------+---------+-----------+
+| |now |previous |difference |
++=========================+======+=========+===========+
+|nb duplicated lines |0 |0 |= |
++-------------------------+------+---------+-----------+
+|percent duplicated lines |0.000 |0.000 |= |
++-------------------------+------+---------+-----------+
+
+
+
+Messages by category
+--------------------
+
++-----------+-------+---------+-----------+
+|type |number |previous |difference |
++===========+=======+=========+===========+
+|convention |0 |0 |= |
++-----------+-------+---------+-----------+
+|refactor |0 |4 |-4.00 |
++-----------+-------+---------+-----------+
+|warning |0 |0 |= |
++-----------+-------+---------+-----------+
+|error |0 |0 |= |
++-----------+-------+---------+-----------+
+
+
+
+
+-------------------------------------------------------------------
+Your code has been rated at 10.00/10 (previous run: 9.17/10, +0.83)
diff --git a/Student/stephen/lesson06/calculator_activity/test.py b/Student/stephen/lesson06/calculator_activity/test.py
new file mode 100644
index 0000000..efbcfaf
--- /dev/null
+++ b/Student/stephen/lesson06/calculator_activity/test.py
@@ -0,0 +1,144 @@
+"""
+Module for unit testing the simple calculator
+"""
+
+
+from unittest import TestCase
+from unittest.mock import MagicMock
+
+from calculator.adder import Adder
+from calculator.subtracter import Subtracter
+from calculator.multiplier import Multiplier
+from calculator.divider import Divider
+
+from calculator.calculator import Calculator
+
+from calculator.exceptions import InsufficientOperands #, DivideByZero
+
+class AdderTests(TestCase):
+
+ def test_adding(self):
+ adder = Adder()
+
+ for i in range(-10, 10):
+ for j in range(-10, 10):
+ self.assertEqual(i + j, adder.calc(i, j))
+
+class SubtracterTests(TestCase):
+
+ def test_subtracting(self):
+ subtracter = Subtracter()
+
+ for i in range(-10, 10):
+ for j in range(-10, 10):
+ self.assertEqual(i - j, subtracter.calc(i, j))
+
+class MultiplierTests(TestCase):
+
+ def test_multiplying(self):
+ multiplier = Multiplier()
+
+ for i in range(-10, 10):
+ for j in range(-10, 10):
+ self.assertEqual(i * j, multiplier.calc(i, j))
+
+class DividerTests(TestCase):
+
+ def test_dividing(self):
+ divider = Divider()
+
+ for i in range(-10, 10):
+ for j in range(1, 10):
+ self.assertEqual(i / j, divider.calc(i, j))
+ for j in range(-10, -1):
+ self.assertEqual(i / j, divider.calc(i, j))
+ # Raise error message when dividing by zero
+ with self.assertRaises(ZeroDivisionError):
+ divider.calc(i, 0)
+
+# test the Calculator class isolated from other methods using dummy methods (MagicMock)
+class CalculatorTests(TestCase):
+
+ def setUp(self):
+ self.adder = Adder()
+ self.subtracter = Subtracter()
+ self.multiplier = Multiplier()
+ self.divider = Divider()
+
+ self.calculator = Calculator(self.adder, self.subtracter, self.multiplier, self.divider)
+
+ def test_insufficient_operands(self):
+ self.calculator.enter_number(0)
+
+ with self.assertRaises(InsufficientOperands):
+ self.calculator.add()
+
+ def test_adder_call(self):
+ self.adder.calc = MagicMock(return_value=0)
+
+ self.calculator.enter_number(1)
+ self.calculator.enter_number(2)
+ self.calculator.add()
+
+ self.adder.calc.assert_called_with(1, 2)
+
+ def test_subtracter_call(self):
+ self.subtracter.calc = MagicMock(return_value=0)
+
+ self.calculator.enter_number(1)
+ self.calculator.enter_number(2)
+ self.calculator.subtract()
+
+ self.subtracter.calc.assert_called_with(1, 2)
+
+ def test_multiplier_call(self):
+ self.multiplier.calc = MagicMock(return_value=0)
+
+ self.calculator.enter_number(1)
+ self.calculator.enter_number(2)
+ self.calculator.multiply()
+
+ self.multiplier.calc.assert_called_with(1, 2)
+
+ def test_divider_call(self):
+ self.divider.calc = MagicMock(return_value=0)
+
+ self.calculator.enter_number(1)
+ self.calculator.enter_number(2)
+ self.calculator.divide()
+
+ self.divider.calc.assert_called_with(1, 2)
+
+ def test_divide_by_zero(self):
+ self.calculator.enter_number(10)
+ self.calculator.enter_number(0)
+
+ with self.assertRaises(ZeroDivisionError):
+ self.calculator.divide()
+
+ self.assertEqual([10], self.calculator.stack)
+
+class ModuleTests(TestCase):
+
+ def test_module(self):
+
+ calculator = Calculator(Adder(), Subtracter(), Multiplier(), Divider())
+
+ calculator.enter_number(5)
+ calculator.enter_number(2)
+
+ calculator.multiply()
+
+ calculator.enter_number(46)
+
+ calculator.add()
+
+ calculator.enter_number(8)
+
+ calculator.divide()
+
+ calculator.enter_number(1)
+
+ result = calculator.subtract()
+
+ self.assertEqual(6, result)
diff --git a/Student/stephen/lesson06/lesson06_activity.zip b/Student/stephen/lesson06/lesson06_activity.zip
new file mode 100644
index 0000000..e576933
Binary files /dev/null and b/Student/stephen/lesson06/lesson06_activity.zip differ
diff --git a/Student/stephen/lesson06/lesson06_assignment.zip b/Student/stephen/lesson06/lesson06_assignment.zip
new file mode 100644
index 0000000..51d783d
Binary files /dev/null and b/Student/stephen/lesson06/lesson06_assignment.zip differ
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/.gitignore b/Student/stephen/lesson06/roman_numerals_exercise/.gitignore
new file mode 100644
index 0000000..004a8d7
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/.gitignore
@@ -0,0 +1,2 @@
+*.pyc
+.coverage
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/.pylintrc b/Student/stephen/lesson06/roman_numerals_exercise/.pylintrc
new file mode 100644
index 0000000..e1bf8fb
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/.pylintrc
@@ -0,0 +1,540 @@
+[MASTER]
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code
+extension-pkg-whitelist=
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Add files or directories matching the regex patterns to the blacklist. The
+# regex matches against base names, not paths.
+ignore-patterns=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Use multiple processes to speed up Pylint.
+jobs=1
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# Specify a configuration file.
+#rcfile=
+
+# When enabled, pylint would attempt to guess common misconfiguration and emit
+# user-friendly hints instead of false-positive error messages
+suggestion-mode=yes
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
+confidence=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+disable=print-statement,
+ parameter-unpacking,
+ unpacking-in-except,
+ old-raise-syntax,
+ backtick,
+ long-suffix,
+ old-ne-operator,
+ old-octal-literal,
+ import-star-module-level,
+ non-ascii-bytes-literal,
+ raw-checker-failed,
+ bad-inline-option,
+ locally-disabled,
+ locally-enabled,
+ file-ignored,
+ suppressed-message,
+ useless-suppression,
+ deprecated-pragma,
+ apply-builtin,
+ basestring-builtin,
+ buffer-builtin,
+ cmp-builtin,
+ coerce-builtin,
+ execfile-builtin,
+ file-builtin,
+ long-builtin,
+ raw_input-builtin,
+ reduce-builtin,
+ standarderror-builtin,
+ unicode-builtin,
+ xrange-builtin,
+ coerce-method,
+ delslice-method,
+ getslice-method,
+ setslice-method,
+ no-absolute-import,
+ old-division,
+ dict-iter-method,
+ dict-view-method,
+ next-method-called,
+ metaclass-assignment,
+ indexing-exception,
+ raising-string,
+ reload-builtin,
+ oct-method,
+ hex-method,
+ nonzero-method,
+ cmp-method,
+ input-builtin,
+ round-builtin,
+ intern-builtin,
+ unichr-builtin,
+ map-builtin-not-iterating,
+ zip-builtin-not-iterating,
+ range-builtin-not-iterating,
+ filter-builtin-not-iterating,
+ using-cmp-argument,
+ eq-without-hash,
+ div-method,
+ idiv-method,
+ rdiv-method,
+ exception-message-attribute,
+ invalid-str-codec,
+ sys-max-int,
+ bad-python3-import,
+ deprecated-string-function,
+ deprecated-str-translate-call,
+ deprecated-itertools-function,
+ deprecated-types-field,
+ next-method-defined,
+ dict-items-not-iterating,
+ dict-keys-not-iterating,
+ dict-values-not-iterating,
+ too-few-public-methods
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
+enable=c-extension-no-member
+
+
+[REPORTS]
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details
+#msg-template=
+
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio).You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Tells whether to display a full report or only the messages
+reports=yes
+
+# Activate the evaluation score.
+score=yes
+
+
+[REFACTORING]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+# Complete name of functions that never returns. When checking for
+# inconsistent-return-statements if a never returning function is called then
+# it will be considered as an explicit return statement and no message will be
+# printed.
+never-returning-functions=optparse.Values,sys.exit
+
+
+[BASIC]
+
+# Naming style matching correct argument names
+argument-naming-style=snake_case
+
+# Regular expression matching correct argument names. Overrides argument-
+# naming-style
+#argument-rgx=
+
+# Naming style matching correct attribute names
+attr-naming-style=snake_case
+
+# Regular expression matching correct attribute names. Overrides attr-naming-
+# style
+#attr-rgx=
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,
+ bar,
+ baz,
+ toto,
+ tutu,
+ tata
+
+# Naming style matching correct class attribute names
+class-attribute-naming-style=any
+
+# Regular expression matching correct class attribute names. Overrides class-
+# attribute-naming-style
+#class-attribute-rgx=
+
+# Naming style matching correct class names
+class-naming-style=PascalCase
+
+# Regular expression matching correct class names. Overrides class-naming-style
+#class-rgx=
+
+# Naming style matching correct constant names
+const-naming-style=UPPER_CASE
+
+# Regular expression matching correct constant names. Overrides const-naming-
+# style
+#const-rgx=
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+# Naming style matching correct function names
+function-naming-style=snake_case
+
+# Regular expression matching correct function names. Overrides function-
+# naming-style
+#function-rgx=
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,
+ j,
+ k,
+ ex,
+ Run,
+ _
+
+# Include a hint for the correct naming format with invalid-name
+include-naming-hint=no
+
+# Naming style matching correct inline iteration names
+inlinevar-naming-style=any
+
+# Regular expression matching correct inline iteration names. Overrides
+# inlinevar-naming-style
+#inlinevar-rgx=
+
+# Naming style matching correct method names
+method-naming-style=snake_case
+
+# Regular expression matching correct method names. Overrides method-naming-
+# style
+#method-rgx=
+
+# Naming style matching correct module names
+module-naming-style=snake_case
+
+# Regular expression matching correct module names. Overrides module-naming-
+# style
+#module-rgx=
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=^_
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+property-classes=abc.abstractproperty
+
+# Naming style matching correct variable names
+variable-naming-style=snake_case
+
+# Regular expression matching correct variable names. Overrides variable-
+# naming-style
+#variable-rgx=
+
+
+[FORMAT]
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )??$
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string=' '
+
+# Maximum number of characters on a single line.
+max-line-length=100
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# List of optional constructs for which whitespace checking is disabled. `dict-
+# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
+# `empty-line` allows space-only lines.
+no-space-check=trailing-comma,
+ dict-separator
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+single-line-class-stmt=no
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+
+[LOGGING]
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format
+logging-modules=logging
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,
+ XXX,
+ TODO
+
+
+[SIMILARITIES]
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+
+[SPELLING]
+
+# Limits count of emitted suggestions for spelling mistakes
+max-spelling-suggestions=4
+
+# Spelling dictionary name. Available dictionaries: none. To make it working
+# install python-enchant package.
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to indicated private dictionary in
+# --spelling-private-dict-file option instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference
+# can return multiple potential results while evaluating a Python object, but
+# some branches might not be evaluated, which results in partial inference. In
+# that case, it might be useful to still emit no-member and other checks for
+# the rest of the inferred objects.
+ignore-on-opaque-inference=yes
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis. It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# Show a hint with possible names when a member name was not found. The aspect
+# of finding the hint is based on edit distance.
+missing-member-hint=yes
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance=1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices=1
+
+
+[VARIABLES]
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables=yes
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,
+ _cb
+
+# A regular expression matching the name of dummy variables (i.e. expectedly
+# not used).
+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*|^ignored_|^unused_
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six.moves,past.builtins,future.builtins
+
+
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+ __new__,
+ setUp
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+ _fields,
+ _replace,
+ _source,
+ _make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Maximum number of boolean expressions in a if statement
+max-bool-expr=5
+
+# Maximum number of branch for function / method body
+max-branches=12
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+
+[IMPORTS]
+
+# Allow wildcard imports from modules that define __all__.
+allow-wildcard-with-all=no
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=optparse,tkinter.tix
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=Exception
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/README.md b/Student/stephen/lesson06/roman_numerals_exercise/README.md
new file mode 100644
index 0000000..a6863ff
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/README.md
@@ -0,0 +1,42 @@
+# Roman Numerals, Advanced Testing Exercise
+
+Before the invention and wide-spread use of the number "zero", many cultures used different ways to represent large numbers. This exercise is based on the Roman method of representing large numbers, known as "Roman numerals."
+
+In the Roman numeral system, certain characters represent certain numbers. The following table gives the number value of the Roman numerals that we will use in this exercise:
+
+* I: 1
+* V: 5
+* X: 10
+* L: 50
+* C: 100
+* D: 500
+* M: 1000
+
+A composite number can be produced by listing several characters, from largest-valued to smallest-valued and adding their values. For example:
+
+* LX: 60
+* LXV: 65
+* MMMD: 3500
+
+Additionally, if a smaller-valued numeral _comes before_ a larger-valued numeral, then that value is subtracted from the total value, rather than added. For example:
+
+* IV: (5 - 1): 4
+* MMIV: 1000 + 1000 + (5 - 1): 2004
+* XC: (100 - 10): 90
+
+There's a version of the Roman numeral system where _any_ smaller-valued numeral which comes before a larger-valued numeral is subtracted from the total, but we won't use that version of numerals.
+
+This repository includes a `RomanToInt` class which can convert a Roman numeral string into an integer. The class works on Roman numeral strings with a value up to 3999. You can use this class at the command line, using the included `main.py`. For example: `python main.py IMMMM`.
+
+## Your Goals
+
+1. Write a comprehensive set of tests into `test.py`.
+2. All of your tests should pass, using: `python -m unittest test.py`.
+3. Running `coverage run --source=roman_numerals -m unittest test.py; coverage report` should give a coverage of 100%.
+4. Satisfy the linter such that `pylint roman_numerals` and `flake8 roman_numerals` show no errors.
+
+## Additional Comments
+
+Feel free to satisfy the linter through any combination of making improvements to the files and/or creating a pylint configuration file which ignores particular errors. If you create a custom configuration file, then be sure to `git include` it in your repository.
+
+For the purposes of this exercise, the code may include some bad style. Feel free to refactor the code if you see opportunities for improvement.
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/coverage_report.txt b/Student/stephen/lesson06/roman_numerals_exercise/coverage_report.txt
new file mode 100644
index 0000000..75778cb
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/coverage_report.txt
@@ -0,0 +1,17 @@
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/roman_numerals_exercise
+$ coverage run --source=roman_numerals -m unittest test
+.........
+----------------------------------------------------------------------
+Ran 9 tests in 0.000s
+
+OK
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/roman_numerals_exercise
+$ coverage report -m
+Name Stmts Miss Cover Missing
+--------------------------------------------------------------
+roman_numerals\__init__.py 0 0 100%
+roman_numerals\roman_to_int.py 25 0 100%
+--------------------------------------------------------------
+TOTAL 25 0 100%
+
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/coverage_html.js b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/coverage_html.js
new file mode 100644
index 0000000..f6f5de2
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/coverage_html.js
@@ -0,0 +1,584 @@
+// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+// For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+// Coverage.py HTML report browser code.
+/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */
+/*global coverage: true, document, window, $ */
+
+coverage = {};
+
+// Find all the elements with shortkey_* class, and use them to assign a shortcut key.
+coverage.assign_shortkeys = function () {
+ $("*[class*='shortkey_']").each(function (i, e) {
+ $.each($(e).attr("class").split(" "), function (i, c) {
+ if (/^shortkey_/.test(c)) {
+ $(document).bind('keydown', c.substr(9), function () {
+ $(e).click();
+ });
+ }
+ });
+ });
+};
+
+// Create the events for the help panel.
+coverage.wire_up_help_panel = function () {
+ $("#keyboard_icon").click(function () {
+ // Show the help panel, and position it so the keyboard icon in the
+ // panel is in the same place as the keyboard icon in the header.
+ $(".help_panel").show();
+ var koff = $("#keyboard_icon").offset();
+ var poff = $("#panel_icon").position();
+ $(".help_panel").offset({
+ top: koff.top-poff.top,
+ left: koff.left-poff.left
+ });
+ });
+ $("#panel_icon").click(function () {
+ $(".help_panel").hide();
+ });
+};
+
+// Create the events for the filter box.
+coverage.wire_up_filter = function () {
+ // Cache elements.
+ var table = $("table.index");
+ var table_rows = table.find("tbody tr");
+ var table_row_names = table_rows.find("td.name a");
+ var no_rows = $("#no_rows");
+
+ // Create a duplicate table footer that we can modify with dynamic summed values.
+ var table_footer = $("table.index tfoot tr");
+ var table_dynamic_footer = table_footer.clone();
+ table_dynamic_footer.attr('class', 'total_dynamic hidden');
+ table_footer.after(table_dynamic_footer);
+
+ // Observe filter keyevents.
+ $("#filter").on("keyup change", $.debounce(150, function (event) {
+ var filter_value = $(this).val();
+
+ if (filter_value === "") {
+ // Filter box is empty, remove all filtering.
+ table_rows.removeClass("hidden");
+
+ // Show standard footer, hide dynamic footer.
+ table_footer.removeClass("hidden");
+ table_dynamic_footer.addClass("hidden");
+
+ // Hide placeholder, show table.
+ if (no_rows.length > 0) {
+ no_rows.hide();
+ }
+ table.show();
+
+ }
+ else {
+ // Filter table items by value.
+ var hidden = 0;
+ var shown = 0;
+
+ // Hide / show elements.
+ $.each(table_row_names, function () {
+ var element = $(this).parents("tr");
+
+ if ($(this).text().indexOf(filter_value) === -1) {
+ // hide
+ element.addClass("hidden");
+ hidden++;
+ }
+ else {
+ // show
+ element.removeClass("hidden");
+ shown++;
+ }
+ });
+
+ // Show placeholder if no rows will be displayed.
+ if (no_rows.length > 0) {
+ if (shown === 0) {
+ // Show placeholder, hide table.
+ no_rows.show();
+ table.hide();
+ }
+ else {
+ // Hide placeholder, show table.
+ no_rows.hide();
+ table.show();
+ }
+ }
+
+ // Manage dynamic header:
+ if (hidden > 0) {
+ // Calculate new dynamic sum values based on visible rows.
+ for (var column = 2; column < 20; column++) {
+ // Calculate summed value.
+ var cells = table_rows.find('td:nth-child(' + column + ')');
+ if (!cells.length) {
+ // No more columns...!
+ break;
+ }
+
+ var sum = 0, numer = 0, denom = 0;
+ $.each(cells.filter(':visible'), function () {
+ var ratio = $(this).data("ratio");
+ if (ratio) {
+ var splitted = ratio.split(" ");
+ numer += parseInt(splitted[0], 10);
+ denom += parseInt(splitted[1], 10);
+ }
+ else {
+ sum += parseInt(this.innerHTML, 10);
+ }
+ });
+
+ // Get footer cell element.
+ var footer_cell = table_dynamic_footer.find('td:nth-child(' + column + ')');
+
+ // Set value into dynamic footer cell element.
+ if (cells[0].innerHTML.indexOf('%') > -1) {
+ // Percentage columns use the numerator and denominator,
+ // and adapt to the number of decimal places.
+ var match = /\.([0-9]+)/.exec(cells[0].innerHTML);
+ var places = 0;
+ if (match) {
+ places = match[1].length;
+ }
+ var pct = numer * 100 / denom;
+ footer_cell.text(pct.toFixed(places) + '%');
+ }
+ else {
+ footer_cell.text(sum);
+ }
+ }
+
+ // Hide standard footer, show dynamic footer.
+ table_footer.addClass("hidden");
+ table_dynamic_footer.removeClass("hidden");
+ }
+ else {
+ // Show standard footer, hide dynamic footer.
+ table_footer.removeClass("hidden");
+ table_dynamic_footer.addClass("hidden");
+ }
+ }
+ }));
+
+ // Trigger change event on setup, to force filter on page refresh
+ // (filter value may still be present).
+ $("#filter").trigger("change");
+};
+
+// Loaded on index.html
+coverage.index_ready = function ($) {
+ // Look for a cookie containing previous sort settings:
+ var sort_list = [];
+ var cookie_name = "COVERAGE_INDEX_SORT";
+ var i;
+
+ // This almost makes it worth installing the jQuery cookie plugin:
+ if (document.cookie.indexOf(cookie_name) > -1) {
+ var cookies = document.cookie.split(";");
+ for (i = 0; i < cookies.length; i++) {
+ var parts = cookies[i].split("=");
+
+ if ($.trim(parts[0]) === cookie_name && parts[1]) {
+ sort_list = eval("[[" + parts[1] + "]]");
+ break;
+ }
+ }
+ }
+
+ // Create a new widget which exists only to save and restore
+ // the sort order:
+ $.tablesorter.addWidget({
+ id: "persistentSort",
+
+ // Format is called by the widget before displaying:
+ format: function (table) {
+ if (table.config.sortList.length === 0 && sort_list.length > 0) {
+ // This table hasn't been sorted before - we'll use
+ // our stored settings:
+ $(table).trigger('sorton', [sort_list]);
+ }
+ else {
+ // This is not the first load - something has
+ // already defined sorting so we'll just update
+ // our stored value to match:
+ sort_list = table.config.sortList;
+ }
+ }
+ });
+
+ // Configure our tablesorter to handle the variable number of
+ // columns produced depending on report options:
+ var headers = [];
+ var col_count = $("table.index > thead > tr > th").length;
+
+ headers[0] = { sorter: 'text' };
+ for (i = 1; i < col_count-1; i++) {
+ headers[i] = { sorter: 'digit' };
+ }
+ headers[col_count-1] = { sorter: 'percent' };
+
+ // Enable the table sorter:
+ $("table.index").tablesorter({
+ widgets: ['persistentSort'],
+ headers: headers
+ });
+
+ coverage.assign_shortkeys();
+ coverage.wire_up_help_panel();
+ coverage.wire_up_filter();
+
+ // Watch for page unload events so we can save the final sort settings:
+ $(window).unload(function () {
+ document.cookie = cookie_name + "=" + sort_list.toString() + "; path=/";
+ });
+};
+
+// -- pyfile stuff --
+
+coverage.pyfile_ready = function ($) {
+ // If we're directed to a particular line number, highlight the line.
+ var frag = location.hash;
+ if (frag.length > 2 && frag[1] === 'n') {
+ $(frag).addClass('highlight');
+ coverage.set_sel(parseInt(frag.substr(2), 10));
+ }
+ else {
+ coverage.set_sel(0);
+ }
+
+ $(document)
+ .bind('keydown', 'j', coverage.to_next_chunk_nicely)
+ .bind('keydown', 'k', coverage.to_prev_chunk_nicely)
+ .bind('keydown', '0', coverage.to_top)
+ .bind('keydown', '1', coverage.to_first_chunk)
+ ;
+
+ $(".button_toggle_run").click(function (evt) {coverage.toggle_lines(evt.target, "run");});
+ $(".button_toggle_exc").click(function (evt) {coverage.toggle_lines(evt.target, "exc");});
+ $(".button_toggle_mis").click(function (evt) {coverage.toggle_lines(evt.target, "mis");});
+ $(".button_toggle_par").click(function (evt) {coverage.toggle_lines(evt.target, "par");});
+
+ coverage.assign_shortkeys();
+ coverage.wire_up_help_panel();
+
+ coverage.init_scroll_markers();
+
+ // Rebuild scroll markers after window high changing
+ $(window).resize(coverage.resize_scroll_markers);
+};
+
+coverage.toggle_lines = function (btn, cls) {
+ btn = $(btn);
+ var hide = "hide_"+cls;
+ if (btn.hasClass(hide)) {
+ $("#source ."+cls).removeClass(hide);
+ btn.removeClass(hide);
+ }
+ else {
+ $("#source ."+cls).addClass(hide);
+ btn.addClass(hide);
+ }
+};
+
+// Return the nth line div.
+coverage.line_elt = function (n) {
+ return $("#t" + n);
+};
+
+// Return the nth line number div.
+coverage.num_elt = function (n) {
+ return $("#n" + n);
+};
+
+// Return the container of all the code.
+coverage.code_container = function () {
+ return $(".linenos");
+};
+
+// Set the selection. b and e are line numbers.
+coverage.set_sel = function (b, e) {
+ // The first line selected.
+ coverage.sel_begin = b;
+ // The next line not selected.
+ coverage.sel_end = (e === undefined) ? b+1 : e;
+};
+
+coverage.to_top = function () {
+ coverage.set_sel(0, 1);
+ coverage.scroll_window(0);
+};
+
+coverage.to_first_chunk = function () {
+ coverage.set_sel(0, 1);
+ coverage.to_next_chunk();
+};
+
+coverage.is_transparent = function (color) {
+ // Different browsers return different colors for "none".
+ return color === "transparent" || color === "rgba(0, 0, 0, 0)";
+};
+
+coverage.to_next_chunk = function () {
+ var c = coverage;
+
+ // Find the start of the next colored chunk.
+ var probe = c.sel_end;
+ var color, probe_line;
+ while (true) {
+ probe_line = c.line_elt(probe);
+ if (probe_line.length === 0) {
+ return;
+ }
+ color = probe_line.css("background-color");
+ if (!c.is_transparent(color)) {
+ break;
+ }
+ probe++;
+ }
+
+ // There's a next chunk, `probe` points to it.
+ var begin = probe;
+
+ // Find the end of this chunk.
+ var next_color = color;
+ while (next_color === color) {
+ probe++;
+ probe_line = c.line_elt(probe);
+ next_color = probe_line.css("background-color");
+ }
+ c.set_sel(begin, probe);
+ c.show_selection();
+};
+
+coverage.to_prev_chunk = function () {
+ var c = coverage;
+
+ // Find the end of the prev colored chunk.
+ var probe = c.sel_begin-1;
+ var probe_line = c.line_elt(probe);
+ if (probe_line.length === 0) {
+ return;
+ }
+ var color = probe_line.css("background-color");
+ while (probe > 0 && c.is_transparent(color)) {
+ probe--;
+ probe_line = c.line_elt(probe);
+ if (probe_line.length === 0) {
+ return;
+ }
+ color = probe_line.css("background-color");
+ }
+
+ // There's a prev chunk, `probe` points to its last line.
+ var end = probe+1;
+
+ // Find the beginning of this chunk.
+ var prev_color = color;
+ while (prev_color === color) {
+ probe--;
+ probe_line = c.line_elt(probe);
+ prev_color = probe_line.css("background-color");
+ }
+ c.set_sel(probe+1, end);
+ c.show_selection();
+};
+
+// Return the line number of the line nearest pixel position pos
+coverage.line_at_pos = function (pos) {
+ var l1 = coverage.line_elt(1),
+ l2 = coverage.line_elt(2),
+ result;
+ if (l1.length && l2.length) {
+ var l1_top = l1.offset().top,
+ line_height = l2.offset().top - l1_top,
+ nlines = (pos - l1_top) / line_height;
+ if (nlines < 1) {
+ result = 1;
+ }
+ else {
+ result = Math.ceil(nlines);
+ }
+ }
+ else {
+ result = 1;
+ }
+ return result;
+};
+
+// Returns 0, 1, or 2: how many of the two ends of the selection are on
+// the screen right now?
+coverage.selection_ends_on_screen = function () {
+ if (coverage.sel_begin === 0) {
+ return 0;
+ }
+
+ var top = coverage.line_elt(coverage.sel_begin);
+ var next = coverage.line_elt(coverage.sel_end-1);
+
+ return (
+ (top.isOnScreen() ? 1 : 0) +
+ (next.isOnScreen() ? 1 : 0)
+ );
+};
+
+coverage.to_next_chunk_nicely = function () {
+ coverage.finish_scrolling();
+ if (coverage.selection_ends_on_screen() === 0) {
+ // The selection is entirely off the screen: select the top line on
+ // the screen.
+ var win = $(window);
+ coverage.select_line_or_chunk(coverage.line_at_pos(win.scrollTop()));
+ }
+ coverage.to_next_chunk();
+};
+
+coverage.to_prev_chunk_nicely = function () {
+ coverage.finish_scrolling();
+ if (coverage.selection_ends_on_screen() === 0) {
+ var win = $(window);
+ coverage.select_line_or_chunk(coverage.line_at_pos(win.scrollTop() + win.height()));
+ }
+ coverage.to_prev_chunk();
+};
+
+// Select line number lineno, or if it is in a colored chunk, select the
+// entire chunk
+coverage.select_line_or_chunk = function (lineno) {
+ var c = coverage;
+ var probe_line = c.line_elt(lineno);
+ if (probe_line.length === 0) {
+ return;
+ }
+ var the_color = probe_line.css("background-color");
+ if (!c.is_transparent(the_color)) {
+ // The line is in a highlighted chunk.
+ // Search backward for the first line.
+ var probe = lineno;
+ var color = the_color;
+ while (probe > 0 && color === the_color) {
+ probe--;
+ probe_line = c.line_elt(probe);
+ if (probe_line.length === 0) {
+ break;
+ }
+ color = probe_line.css("background-color");
+ }
+ var begin = probe + 1;
+
+ // Search forward for the last line.
+ probe = lineno;
+ color = the_color;
+ while (color === the_color) {
+ probe++;
+ probe_line = c.line_elt(probe);
+ color = probe_line.css("background-color");
+ }
+
+ coverage.set_sel(begin, probe);
+ }
+ else {
+ coverage.set_sel(lineno);
+ }
+};
+
+coverage.show_selection = function () {
+ var c = coverage;
+
+ // Highlight the lines in the chunk
+ c.code_container().find(".highlight").removeClass("highlight");
+ for (var probe = c.sel_begin; probe > 0 && probe < c.sel_end; probe++) {
+ c.num_elt(probe).addClass("highlight");
+ }
+
+ c.scroll_to_selection();
+};
+
+coverage.scroll_to_selection = function () {
+ // Scroll the page if the chunk isn't fully visible.
+ if (coverage.selection_ends_on_screen() < 2) {
+ // Need to move the page. The html,body trick makes it scroll in all
+ // browsers, got it from http://stackoverflow.com/questions/3042651
+ var top = coverage.line_elt(coverage.sel_begin);
+ var top_pos = parseInt(top.offset().top, 10);
+ coverage.scroll_window(top_pos - 30);
+ }
+};
+
+coverage.scroll_window = function (to_pos) {
+ $("html,body").animate({scrollTop: to_pos}, 200);
+};
+
+coverage.finish_scrolling = function () {
+ $("html,body").stop(true, true);
+};
+
+coverage.init_scroll_markers = function () {
+ var c = coverage;
+ // Init some variables
+ c.lines_len = $('td.text p').length;
+ c.body_h = $('body').height();
+ c.header_h = $('div#header').height();
+ c.missed_lines = $('td.text p.mis, td.text p.par');
+
+ // Build html
+ c.resize_scroll_markers();
+};
+
+coverage.resize_scroll_markers = function () {
+ var c = coverage,
+ min_line_height = 3,
+ max_line_height = 10,
+ visible_window_h = $(window).height();
+
+ $('#scroll_marker').remove();
+ // Don't build markers if the window has no scroll bar.
+ if (c.body_h <= visible_window_h) {
+ return;
+ }
+
+ $("body").append("
");
+ var scroll_marker = $('#scroll_marker'),
+ marker_scale = scroll_marker.height() / c.body_h,
+ line_height = scroll_marker.height() / c.lines_len;
+
+ // Line height must be between the extremes.
+ if (line_height > min_line_height) {
+ if (line_height > max_line_height) {
+ line_height = max_line_height;
+ }
+ }
+ else {
+ line_height = min_line_height;
+ }
+
+ var previous_line = -99,
+ last_mark,
+ last_top;
+
+ c.missed_lines.each(function () {
+ var line_top = Math.round($(this).offset().top * marker_scale),
+ id_name = $(this).attr('id'),
+ line_number = parseInt(id_name.substring(1, id_name.length));
+
+ if (line_number === previous_line + 1) {
+ // If this solid missed block just make previous mark higher.
+ last_mark.css({
+ 'height': line_top + line_height - last_top
+ });
+ }
+ else {
+ // Add colored line in scroll_marker block.
+ scroll_marker.append('
');
+ last_mark = $('#m' + line_number);
+ last_mark.css({
+ 'height': line_height,
+ 'top': line_top
+ });
+ last_top = line_top;
+ }
+
+ previous_line = line_number;
+ });
+};
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/index.html b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/index.html
new file mode 100644
index 0000000..60cd79e
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/index.html
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+ Coverage report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ n
+ s
+ m
+ x
+
+ c change column sorting
+
+
+
+
+
+
+
+
+ No items found using the specified filter.
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.ba-throttle-debounce.min.js b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.ba-throttle-debounce.min.js
new file mode 100644
index 0000000..648fe5d
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.ba-throttle-debounce.min.js
@@ -0,0 +1,9 @@
+/*
+ * jQuery throttle / debounce - v1.1 - 3/7/2010
+ * http://benalman.com/projects/jquery-throttle-debounce-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this);
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.hotkeys.js b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.hotkeys.js
new file mode 100644
index 0000000..09b21e0
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.hotkeys.js
@@ -0,0 +1,99 @@
+/*
+ * jQuery Hotkeys Plugin
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ *
+ * Based upon the plugin by Tzury Bar Yochay:
+ * http://github.com/tzuryby/hotkeys
+ *
+ * Original idea by:
+ * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
+*/
+
+(function(jQuery){
+
+ jQuery.hotkeys = {
+ version: "0.8",
+
+ specialKeys: {
+ 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
+ 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
+ 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
+ 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
+ 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
+ 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
+ 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
+ },
+
+ shiftNums: {
+ "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
+ "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
+ ".": ">", "/": "?", "\\": "|"
+ }
+ };
+
+ function keyHandler( handleObj ) {
+ // Only care when a possible input has been specified
+ if ( typeof handleObj.data !== "string" ) {
+ return;
+ }
+
+ var origHandler = handleObj.handler,
+ keys = handleObj.data.toLowerCase().split(" ");
+
+ handleObj.handler = function( event ) {
+ // Don't fire in text-accepting inputs that we didn't directly bind to
+ if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
+ event.target.type === "text") ) {
+ return;
+ }
+
+ // Keypress represents characters, not special keys
+ var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
+ character = String.fromCharCode( event.which ).toLowerCase(),
+ key, modif = "", possible = {};
+
+ // check combinations (alt|ctrl|shift+anything)
+ if ( event.altKey && special !== "alt" ) {
+ modif += "alt+";
+ }
+
+ if ( event.ctrlKey && special !== "ctrl" ) {
+ modif += "ctrl+";
+ }
+
+ // TODO: Need to make sure this works consistently across platforms
+ if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
+ modif += "meta+";
+ }
+
+ if ( event.shiftKey && special !== "shift" ) {
+ modif += "shift+";
+ }
+
+ if ( special ) {
+ possible[ modif + special ] = true;
+
+ } else {
+ possible[ modif + character ] = true;
+ possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
+
+ // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
+ if ( modif === "shift+" ) {
+ possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
+ }
+ }
+
+ for ( var i = 0, l = keys.length; i < l; i++ ) {
+ if ( possible[ keys[i] ] ) {
+ return origHandler.apply( this, arguments );
+ }
+ }
+ };
+ }
+
+ jQuery.each([ "keydown", "keyup", "keypress" ], function() {
+ jQuery.event.special[ this ] = { add: keyHandler };
+ });
+
+})( jQuery );
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.isonscreen.js b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.isonscreen.js
new file mode 100644
index 0000000..0182ebd
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.isonscreen.js
@@ -0,0 +1,53 @@
+/* Copyright (c) 2010
+ * @author Laurence Wheway
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * @version 1.2.0
+ */
+(function($) {
+ jQuery.extend({
+ isOnScreen: function(box, container) {
+ //ensure numbers come in as intgers (not strings) and remove 'px' is it's there
+ for(var i in box){box[i] = parseFloat(box[i])};
+ for(var i in container){container[i] = parseFloat(container[i])};
+
+ if(!container){
+ container = {
+ left: $(window).scrollLeft(),
+ top: $(window).scrollTop(),
+ width: $(window).width(),
+ height: $(window).height()
+ }
+ }
+
+ if( box.left+box.width-container.left > 0 &&
+ box.left < container.width+container.left &&
+ box.top+box.height-container.top > 0 &&
+ box.top < container.height+container.top
+ ) return true;
+ return false;
+ }
+ })
+
+
+ jQuery.fn.isOnScreen = function (container) {
+ for(var i in container){container[i] = parseFloat(container[i])};
+
+ if(!container){
+ container = {
+ left: $(window).scrollLeft(),
+ top: $(window).scrollTop(),
+ width: $(window).width(),
+ height: $(window).height()
+ }
+ }
+
+ if( $(this).offset().left+$(this).width()-container.left > 0 &&
+ $(this).offset().left < container.width+container.left &&
+ $(this).offset().top+$(this).height()-container.top > 0 &&
+ $(this).offset().top < container.height+container.top
+ ) return true;
+ return false;
+ }
+})(jQuery);
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.min.js b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.min.js
new file mode 100644
index 0000000..d1608e3
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML=" ",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML=" ","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML=" ",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
+if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" a ",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML=" ",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h ]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""," "],legend:[1,""," "],area:[1,""," "],param:[1,""," "],thead:[1,""],tr:[2,""],col:[2,""],td:[3,""],_default:k.htmlSerialize?[0,"",""]:[1,"X","
"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML=" a ",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")
+},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();ca ",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m});
\ No newline at end of file
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.tablesorter.min.js b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.tablesorter.min.js
new file mode 100644
index 0000000..64c7007
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/jquery.tablesorter.min.js
@@ -0,0 +1,2 @@
+
+(function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i
1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($(' ').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;ib)?1:0));};function sortTextDesc(a,b){return((ba)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j 0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i
+
+
+
+
+
+
+ Coverage for roman_numerals\__init__.py: 100%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ r
+ m
+ x
+ p toggle line displays
+
+
+ j
+ k next/prev highlighted chunk
+
+
+ 0 (zero) top of page
+
+
+ 1 (one) first highlighted chunk
+
+
+
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/roman_numerals_roman_to_int_py.html b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/roman_numerals_roman_to_int_py.html
new file mode 100644
index 0000000..eb11463
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/roman_numerals_roman_to_int_py.html
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
+
+ Coverage for roman_numerals\roman_to_int.py: 100%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hot-keys on this page
+
+
+ r
+ m
+ x
+ p toggle line displays
+
+
+ j
+ k next/prev highlighted chunk
+
+
+ 0 (zero) top of page
+
+
+ 1 (one) first highlighted chunk
+
+
+
+
+
+
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+
+
+
+"""
+Module for converting roman numerals to integers
+"""
+
+
+class RomanToInt ( object ) :
+ """
+ Class to create the roman to integer calculator
+ """
+ @ staticmethod
+ def value_of ( roman_numeral ) :
+ """
+ Method defining conversion functions for each numeral
+ """
+ if roman_numeral == 'I' :
+ result = 1
+ elif roman_numeral == 'V' :
+ result = 5
+ elif roman_numeral == 'X' :
+ result = 10
+ elif roman_numeral == 'L' :
+ result = 50
+ elif roman_numeral == 'C' :
+ result = 100
+ elif roman_numeral == 'D' :
+ result = 500
+ elif roman_numeral == 'M' :
+ result = 1000
+ else :
+ raise ValueError (
+ "Provided character must be one of: I V X L C D M." )
+ return result
+
+ @ classmethod
+ def convert ( cls , roman_numerals ) :
+ """
+ Method that calculates the integer after converting to values
+ """
+ result = 0
+ for i , roman_numeral in enumerate ( roman_numerals ) :
+ if ( ( i + 1 ) < len ( roman_numerals ) ) and (
+ cls . value_of ( roman_numeral ) <
+ cls . value_of ( roman_numerals [ i + 1 ] ) ) :
+ result -= cls . value_of ( roman_numeral )
+ else :
+ result += cls . value_of ( roman_numeral )
+
+ return result
+
+
+
+
+
+
+
+
+
+
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/status.json b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/status.json
new file mode 100644
index 0000000..15bfaea
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/status.json
@@ -0,0 +1 @@
+{"format":1,"version":"4.5.1","settings":"b3a0bff7154d5bbec34fcac359c54f68","files":{"roman_numerals___init___py":{"hash":"182b2dca469bf063cbcf996d517b03da","index":{"nums":[1,0,0,0,0,0,0],"html_filename":"roman_numerals___init___py.html","relative_filename":"roman_numerals\\__init__.py"}},"roman_numerals_roman_to_int_py":{"hash":"5401b3903f7020a3052a74a6ef7f522a","index":{"nums":[1,25,0,0,0,0,0],"html_filename":"roman_numerals_roman_to_int_py.html","relative_filename":"roman_numerals\\roman_to_int.py"}}}}
\ No newline at end of file
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/style.css b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/style.css
new file mode 100644
index 0000000..86b8209
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/htmlcov/style.css
@@ -0,0 +1,375 @@
+/* Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 */
+/* For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt */
+
+/* CSS styles for coverage.py. */
+
+/* Page-wide styles */
+html, body, h1, h2, h3, p, table, td, th {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-weight: inherit;
+ font-style: inherit;
+ font-size: 100%;
+ font-family: inherit;
+ vertical-align: baseline;
+ }
+
+/* Set baseline grid to 16 pt. */
+body {
+ font-family: georgia, serif;
+ font-size: 1em;
+ }
+
+html>body {
+ font-size: 16px;
+ }
+
+/* Set base font size to 12/16 */
+p {
+ font-size: .75em; /* 12/16 */
+ line-height: 1.33333333em; /* 16/12 */
+ }
+
+table {
+ border-collapse: collapse;
+ }
+td {
+ vertical-align: top;
+}
+table tr.hidden {
+ display: none !important;
+ }
+
+p#no_rows {
+ display: none;
+ font-size: 1.2em;
+ }
+
+a.nav {
+ text-decoration: none;
+ color: inherit;
+ }
+a.nav:hover {
+ text-decoration: underline;
+ color: inherit;
+ }
+
+/* Page structure */
+#header {
+ background: #f8f8f8;
+ width: 100%;
+ border-bottom: 1px solid #eee;
+ }
+
+#source {
+ padding: 1em;
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ }
+
+.indexfile #footer {
+ margin: 1em 3em;
+ }
+
+.pyfile #footer {
+ margin: 1em 1em;
+ }
+
+#footer .content {
+ padding: 0;
+ font-size: 85%;
+ font-family: verdana, sans-serif;
+ color: #666666;
+ font-style: italic;
+ }
+
+#index {
+ margin: 1em 0 0 3em;
+ }
+
+/* Header styles */
+#header .content {
+ padding: 1em 3em;
+ }
+
+h1 {
+ font-size: 1.25em;
+ display: inline-block;
+}
+
+#filter_container {
+ display: inline-block;
+ float: right;
+ margin: 0 2em 0 0;
+}
+#filter_container input {
+ width: 10em;
+}
+
+h2.stats {
+ margin-top: .5em;
+ font-size: 1em;
+}
+.stats span {
+ border: 1px solid;
+ padding: .1em .25em;
+ margin: 0 .1em;
+ cursor: pointer;
+ border-color: #999 #ccc #ccc #999;
+}
+.stats span.hide_run, .stats span.hide_exc,
+.stats span.hide_mis, .stats span.hide_par,
+.stats span.par.hide_run.hide_par {
+ border-color: #ccc #999 #999 #ccc;
+}
+.stats span.par.hide_run {
+ border-color: #999 #ccc #ccc #999;
+}
+
+.stats span.run {
+ background: #ddffdd;
+}
+.stats span.exc {
+ background: #eeeeee;
+}
+.stats span.mis {
+ background: #ffdddd;
+}
+.stats span.hide_run {
+ background: #eeffee;
+}
+.stats span.hide_exc {
+ background: #f5f5f5;
+}
+.stats span.hide_mis {
+ background: #ffeeee;
+}
+.stats span.par {
+ background: #ffffaa;
+}
+.stats span.hide_par {
+ background: #ffffcc;
+}
+
+/* Help panel */
+#keyboard_icon {
+ float: right;
+ margin: 5px;
+ cursor: pointer;
+}
+
+.help_panel {
+ position: absolute;
+ background: #ffffcc;
+ padding: .5em;
+ border: 1px solid #883;
+ display: none;
+}
+
+.indexfile .help_panel {
+ width: 20em; height: 4em;
+}
+
+.pyfile .help_panel {
+ width: 16em; height: 8em;
+}
+
+.help_panel .legend {
+ font-style: italic;
+ margin-bottom: 1em;
+}
+
+#panel_icon {
+ float: right;
+ cursor: pointer;
+}
+
+.keyhelp {
+ margin: .75em;
+}
+
+.keyhelp .key {
+ border: 1px solid black;
+ border-color: #888 #333 #333 #888;
+ padding: .1em .35em;
+ font-family: monospace;
+ font-weight: bold;
+ background: #eee;
+}
+
+/* Source file styles */
+.linenos p {
+ text-align: right;
+ margin: 0;
+ padding: 0 .5em;
+ color: #999999;
+ font-family: verdana, sans-serif;
+ font-size: .625em; /* 10/16 */
+ line-height: 1.6em; /* 16/10 */
+ }
+.linenos p.highlight {
+ background: #ffdd00;
+ }
+.linenos p a {
+ text-decoration: none;
+ color: #999999;
+ }
+.linenos p a:hover {
+ text-decoration: underline;
+ color: #999999;
+ }
+
+td.text {
+ width: 100%;
+ }
+.text p {
+ margin: 0;
+ padding: 0 0 0 .5em;
+ border-left: 2px solid #ffffff;
+ white-space: pre;
+ position: relative;
+ }
+
+.text p.mis {
+ background: #ffdddd;
+ border-left: 2px solid #ff0000;
+ }
+.text p.run, .text p.run.hide_par {
+ background: #ddffdd;
+ border-left: 2px solid #00ff00;
+ }
+.text p.exc {
+ background: #eeeeee;
+ border-left: 2px solid #808080;
+ }
+.text p.par, .text p.par.hide_run {
+ background: #ffffaa;
+ border-left: 2px solid #eeee99;
+ }
+.text p.hide_run, .text p.hide_exc, .text p.hide_mis, .text p.hide_par,
+.text p.hide_run.hide_par {
+ background: inherit;
+ }
+
+.text span.annotate {
+ font-family: georgia;
+ color: #666;
+ float: right;
+ padding-right: .5em;
+ }
+.text p.hide_par span.annotate {
+ display: none;
+ }
+.text span.annotate.long {
+ display: none;
+ }
+.text p:hover span.annotate.long {
+ display: block;
+ max-width: 50%;
+ white-space: normal;
+ float: right;
+ position: absolute;
+ top: 1.75em;
+ right: 1em;
+ width: 30em;
+ height: auto;
+ color: #333;
+ background: #ffffcc;
+ border: 1px solid #888;
+ padding: .25em .5em;
+ z-index: 999;
+ border-radius: .2em;
+ box-shadow: #cccccc .2em .2em .2em;
+ }
+
+/* Syntax coloring */
+.text .com {
+ color: green;
+ font-style: italic;
+ line-height: 1px;
+ }
+.text .key {
+ font-weight: bold;
+ line-height: 1px;
+ }
+.text .str {
+ color: #000080;
+ }
+
+/* index styles */
+#index td, #index th {
+ text-align: right;
+ width: 5em;
+ padding: .25em .5em;
+ border-bottom: 1px solid #eee;
+ }
+#index th {
+ font-style: italic;
+ color: #333;
+ border-bottom: 1px solid #ccc;
+ cursor: pointer;
+ }
+#index th:hover {
+ background: #eee;
+ border-bottom: 1px solid #999;
+ }
+#index td.left, #index th.left {
+ padding-left: 0;
+ }
+#index td.right, #index th.right {
+ padding-right: 0;
+ }
+#index th.headerSortDown, #index th.headerSortUp {
+ border-bottom: 1px solid #000;
+ white-space: nowrap;
+ background: #eee;
+ }
+#index th.headerSortDown:after {
+ content: " ↓";
+}
+#index th.headerSortUp:after {
+ content: " ↑";
+}
+#index td.name, #index th.name {
+ text-align: left;
+ width: auto;
+ }
+#index td.name a {
+ text-decoration: none;
+ color: #000;
+ }
+#index tr.total,
+#index tr.total_dynamic {
+ }
+#index tr.total td,
+#index tr.total_dynamic td {
+ font-weight: bold;
+ border-top: 1px solid #ccc;
+ border-bottom: none;
+ }
+#index tr.file:hover {
+ background: #eeeeee;
+ }
+#index tr.file:hover td.name {
+ text-decoration: underline;
+ color: #000;
+ }
+
+/* scroll marker styles */
+#scroll_marker {
+ position: fixed;
+ right: 0;
+ top: 0;
+ width: 16px;
+ height: 100%;
+ background: white;
+ border-left: 1px solid #eee;
+ }
+
+#scroll_marker .marker {
+ background: #eedddd;
+ position: absolute;
+ min-height: 3px;
+ width: 100%;
+ }
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/main.py b/Student/stephen/lesson06/roman_numerals_exercise/main.py
new file mode 100644
index 0000000..2245d78
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/main.py
@@ -0,0 +1,10 @@
+import sys
+
+from roman_numerals.roman_to_int import RomanToInt
+
+
+if __name__ == "__main__":
+ s = sys.argv[1]
+
+ print("The Roman numerals {} are {} in decimal.".format(s, RomanToInt.convert(s)))
+
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/pylint_flake8_output.txt b/Student/stephen/lesson06/roman_numerals_exercise/pylint_flake8_output.txt
new file mode 100644
index 0000000..d39dddb
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/pylint_flake8_output.txt
@@ -0,0 +1,93 @@
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/roman_numerals_exercise
+$ python -m pylint roman_numerals
+Using config file C:\Users\ssouk\Documents\Python\Python Programming 220 AC\Lesson06\roman_numerals_exercise\.pylintrc
+
+
+Report
+======
+25 statements analysed.
+
+Statistics by type
+------------------
+
++---------+-------+-----------+-----------+------------+---------+
+|type |number |old number |difference |%documented |%badname |
++=========+=======+===========+===========+============+=========+
+|module |2 |2 |= |100.00 |0.00 |
++---------+-------+-----------+-----------+------------+---------+
+|class |1 |1 |= |100.00 |0.00 |
++---------+-------+-----------+-----------+------------+---------+
+|method |2 |2 |= |100.00 |0.00 |
++---------+-------+-----------+-----------+------------+---------+
+|function |0 |0 |= |0 |0 |
++---------+-------+-----------+-----------+------------+---------+
+
+
+
+Raw metrics
+-----------
+
++----------+-------+------+---------+-----------+
+|type |number |% |previous |difference |
++==========+=======+======+=========+===========+
+|code |33 |67.35 |32 |+1.00 |
++----------+-------+------+---------+-----------+
+|docstring |12 |24.49 |12 |= |
++----------+-------+------+---------+-----------+
+|comment |0 |0.00 |0 |= |
++----------+-------+------+---------+-----------+
+|empty |4 |8.16 |4 |= |
++----------+-------+------+---------+-----------+
+
+
+
+Duplication
+-----------
+
++-------------------------+------+---------+-----------+
+| |now |previous |difference |
++=========================+======+=========+===========+
+|nb duplicated lines |0 |0 |= |
++-------------------------+------+---------+-----------+
+|percent duplicated lines |0.000 |0.000 |= |
++-------------------------+------+---------+-----------+
+
+
+
+Messages by category
+--------------------
+
++-----------+-------+---------+-----------+
+|type |number |previous |difference |
++===========+=======+=========+===========+
+|convention |0 |0 |= |
++-----------+-------+---------+-----------+
+|refactor |0 |1 |-1.00 |
++-----------+-------+---------+-----------+
+|warning |0 |0 |= |
++-----------+-------+---------+-----------+
+|error |0 |0 |= |
++-----------+-------+---------+-----------+
+
+
+
+
+-------------------------------------------------------------------
+Your code has been rated at 10.00/10 (previous run: 9.58/10, +0.42)
+
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/roman_numerals_exercise
+$ flake8 roman_numerals
+roman_numerals\roman_to_int.py:5:1: E302 expected 2 blank lines, found 1
+roman_numerals\roman_to_int.py:29:80: E501 line too long (81 > 79 characters)
+roman_numerals\roman_to_int.py:40:80: E501 line too long (87 > 79 characters)
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/roman_numerals_exercise
+$ flake8 roman_numerals
+roman_numerals\roman_to_int.py:42:80: E501 line too long (87 > 79 characters)
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/roman_numerals_exercise
+$ flake8 roman_numerals
+
+ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson06/roman_numerals_exercise
+$
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/roman_numerals/__init__.py b/Student/stephen/lesson06/roman_numerals_exercise/roman_numerals/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/roman_numerals/roman_to_int.py b/Student/stephen/lesson06/roman_numerals_exercise/roman_numerals/roman_to_int.py
new file mode 100644
index 0000000..e3869c5
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/roman_numerals/roman_to_int.py
@@ -0,0 +1,48 @@
+"""
+Module for converting roman numerals to integers
+"""
+
+
+class RomanToInt(object):
+ """
+ Class to create the roman to integer calculator
+ """
+ @staticmethod
+ def value_of(roman_numeral):
+ """
+ Method defining conversion functions for each numeral
+ """
+ if roman_numeral == 'I':
+ result = 1
+ elif roman_numeral == 'V':
+ result = 5
+ elif roman_numeral == 'X':
+ result = 10
+ elif roman_numeral == 'L':
+ result = 50
+ elif roman_numeral == 'C':
+ result = 100
+ elif roman_numeral == 'D':
+ result = 500
+ elif roman_numeral == 'M':
+ result = 1000
+ else:
+ raise ValueError(
+ "Provided character must be one of: I V X L C D M.")
+ return result
+
+ @classmethod
+ def convert(cls, roman_numerals):
+ """
+ Method that calculates the integer after converting to values
+ """
+ result = 0
+ for i, roman_numeral in enumerate(roman_numerals):
+ if ((i + 1) < len(roman_numerals)) and (
+ cls.value_of(roman_numeral) <
+ cls.value_of(roman_numerals[i + 1])):
+ result -= cls.value_of(roman_numeral)
+ else:
+ result += cls.value_of(roman_numeral)
+
+ return result
diff --git a/Student/stephen/lesson06/roman_numerals_exercise/test.py b/Student/stephen/lesson06/roman_numerals_exercise/test.py
new file mode 100644
index 0000000..b065a84
--- /dev/null
+++ b/Student/stephen/lesson06/roman_numerals_exercise/test.py
@@ -0,0 +1,39 @@
+"""
+Module for unit testing roman numerals to integer program
+"""
+
+
+import unittest
+
+from roman_numerals.roman_to_int import RomanToInt
+
+
+class TestRomanToInteger(unittest.TestCase):
+
+ def test_single_I(self):
+ self.assertEqual(RomanToInt.convert('I'), 1)
+
+ def test_single_V(self):
+ self.assertEqual(RomanToInt.convert('V'), 5)
+
+ def test_single_X(self):
+ self.assertEqual(RomanToInt.convert('X'), 10)
+
+ def test_single_L(self):
+ self.assertEqual(RomanToInt.convert('L'), 50)
+
+ def test_single_C(self):
+ self.assertEqual(RomanToInt.convert('C'), 100)
+
+ def test_single_D(self):
+ self.assertEqual(RomanToInt.convert('D'), 500)
+
+ def test_single_M(self):
+ self.assertEqual(RomanToInt.convert('M'), 1000)
+
+ def test_multiple_numerals(self):
+ self.assertEqual(RomanToInt.convert('MMIV'), 2004)
+
+ def test_value_error(self):
+ with self.assertRaises(ValueError):
+ RomanToInt.convert('ZZZ')
diff --git a/Student/stephen/lesson07/lesson07_activity/__pycache__/personjob_model.cpython-36.pyc b/Student/stephen/lesson07/lesson07_activity/__pycache__/personjob_model.cpython-36.pyc
new file mode 100644
index 0000000..82f6a8d
Binary files /dev/null and b/Student/stephen/lesson07/lesson07_activity/__pycache__/personjob_model.cpython-36.pyc differ
diff --git a/Student/stephen/lesson07/lesson07_activity/create_personjob.py b/Student/stephen/lesson07/lesson07_activity/create_personjob.py
new file mode 100644
index 0000000..3bb8db4
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_activity/create_personjob.py
@@ -0,0 +1,101 @@
+"""
+ Simple database examle with Peewee ORM, sqlite and Python
+ Here we define the schema
+ For the Lesson 7 activity I added the class for the Department table
+ I also use the feature that autogenerates ids for the PK
+"""
+
+import logging
+from peewee import *
+# need this library for hybrid properties
+from playhouse.hybrid import *
+from datetime import date
+
+logging.basicConfig(level=logging.INFO) # change to INFO to show info log, change to CRITICAL to silence logger
+logger = logging.getLogger(__name__)
+
+logger.info('One off program to build the classes from the model in the database')
+
+logger.info('Here we define our data (the schema)')
+logger.info('First name and connect to a database (sqlite here)')
+
+logger.info('The next 3 lines of code are the only database specific code')
+
+database = SqliteDatabase('personjob.db')
+database.connect()
+database.execute_sql('PRAGMA foreign_keys = ON;') # needed for sqlite only
+
+logger.info('This means we can easily switch to a different database')
+logger.info('Enable the Peewee magic! This base class does it all')
+logger.info('By inheritance only we keep our model (almost) technology neutral')
+
+class BaseModel(Model):
+ class Meta:
+ database = database
+
+class Person(BaseModel):
+ """
+ This class defines Person, which maintains details of someone
+ for whom we want to research career to date.
+ """
+
+ logger.info('Specify the fields in our model, their lengths and if mandatory')
+ logger.info('Using the autogenerated PK')
+
+ person_name = CharField(max_length = 50)
+ lives_in_town = CharField(max_length = 40)
+ nickname = CharField(max_length = 20, null = True)
+
+
+class Department(BaseModel):
+ """
+ This class defines Department, which maintains details about a department
+ """
+
+ department_code = CharField(max_length = 4)
+ department_name = CharField(max_length = 40)
+ manager = CharField(max_length = 50)
+
+class Job(BaseModel):
+ """
+ This class defines Job, which maintains details of past Jobs
+ held by a Person. Added FK to Department for lesson 7 activity
+ """
+
+ logger.info('Now the Job class with a similar approach')
+ job_name = CharField(max_length = 30)
+ logger.info('Dates')
+ start_date = DateField(formats = 'YYYY-MM-DD')
+ end_date = DateField(formats = 'YYYY-MM-DD')
+
+ # # wasn't sure how else to get the number of days between end_date and start_date so calculated
+ # # a date diff from datetime library and converted it to the number of days.
+ @hybrid_property
+ def days_on_job(self):
+ return (date(int(self.end_date[0:4]), int(self.end_date[5:7]), int(self.end_date[-2:])) -
+ date(int(self.start_date[0:4]), int(self.start_date[5:7]), int(self.start_date[-2:]))).days
+
+ @days_on_job.expression
+ def days_on_job(cls):
+ return fn.julianday(cls.end_date) - fn.julianday(cls.start_date)
+
+ logger.info('Number')
+ salary = DecimalField(max_digits = 7, decimal_places = 2)
+
+ logger.info('Which person had the Job')
+ logger.info('Use the autogenerated id from Person table as FK')
+ person_id = ForeignKeyField(Person, related_name='was_filled_by', null=False)
+
+ logger.info('Which department the job belonged to')
+ logger.info('Use the autogenerated id from Department table as FK')
+ dept_id = ForeignKeyField(Department, null=False)
+
+
+
+database.create_tables([
+ Job,
+ Person,
+ Department
+ ])
+
+database.close()
diff --git a/Student/stephen/lesson07/lesson07_activity/lesson07_activity.zip b/Student/stephen/lesson07/lesson07_activity/lesson07_activity.zip
new file mode 100644
index 0000000..09f625c
Binary files /dev/null and b/Student/stephen/lesson07/lesson07_activity/lesson07_activity.zip differ
diff --git a/Student/stephen/lesson07/lesson07_activity/personjob.db b/Student/stephen/lesson07/lesson07_activity/personjob.db
new file mode 100644
index 0000000..5241ce8
Binary files /dev/null and b/Student/stephen/lesson07/lesson07_activity/personjob.db differ
diff --git a/Student/stephen/lesson07/lesson07_activity/personjob_model.py b/Student/stephen/lesson07/lesson07_activity/personjob_model.py
new file mode 100644
index 0000000..402db9a
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_activity/personjob_model.py
@@ -0,0 +1,66 @@
+"""
+ Simple database examle with Peewee ORM, sqlite and Python
+ Here we define the schema
+ For the Lesson 7 activity I added the class for the Department table
+ I also use the autogenerated ids for the PK
+"""
+
+from peewee import *
+from datetime import date
+# need this library for hybrid properties
+from playhouse.hybrid import *
+
+database = SqliteDatabase('personjob.db')
+database.connect()
+database.execute_sql('PRAGMA foreign_keys = ON;')
+
+class BaseModel(Model):
+ class Meta:
+ database = database
+
+
+class Person(BaseModel):
+ """
+ This class defines Person, which maintains details of someone
+ for whom we want to research career to date.
+ """
+
+ person_name = CharField(max_length = 50)
+ lives_in_town = CharField(max_length = 40)
+ nickname = CharField(max_length = 20, null = True)
+
+
+class Department(BaseModel):
+ """
+ This class defines Department, which maintains details about a department
+ """
+
+ department_code = CharField(max_length = 4)
+ department_name = CharField(max_length = 40)
+ manager = CharField(max_length = 50)
+
+class Job(BaseModel):
+ """
+ This class defines Job, which maintains details of past Jobs
+ held by a Person. Added FK to Department for lesson 7 activity
+ """
+
+ job_name = CharField(max_length = 30)
+ start_date = DateField(formats = 'YYYY-MM-DD')
+ end_date = DateField(formats = 'YYYY-MM-DD')
+
+ # # wasn't sure how else to get the number of days between end_date and start_date so calculated
+ # # a date diff from datetime library and converted it to the number of days.
+ @hybrid_property
+ def days_on_job(self):
+ return (date(int(self.end_date[0:4]), int(self.end_date[5:7]), int(self.end_date[-2:])) -
+ date(int(self.start_date[0:4]), int(self.start_date[5:7]), int(self.start_date[-2:]))).days
+
+ @days_on_job.expression
+ def days_on_job(cls):
+ return fn.julianday(cls.end_date) - fn.julianday(cls.start_date)
+
+
+ salary = DecimalField(max_digits = 7, decimal_places = 2)
+ person_id = ForeignKeyField(Person, related_name='was_filled_by', null=False)
+ dept_id = ForeignKeyField(Department, null=False)
diff --git a/Student/stephen/lesson07/lesson07_activity/populate_db.py b/Student/stephen/lesson07/lesson07_activity/populate_db.py
new file mode 100644
index 0000000..162c42e
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_activity/populate_db.py
@@ -0,0 +1,179 @@
+"""
+Module for populating the personjob database
+"""
+
+from personjob_model import *
+
+import logging
+
+def populate_person():
+ """
+ add person data to database
+ """
+
+ logging.basicConfig(level=logging.INFO)
+ logger = logging.getLogger(__name__)
+
+ database = SqliteDatabase('personjob.db')
+
+ logger.info('Working with Person class')
+ logger.info('Note how I use constants and a list of tuples as a simple schema')
+ logger.info('Normally you probably will have prompted for this from a user')
+
+ PERSON_NAME = 0
+ LIVES_IN_TOWN = 1
+ NICKNAME = 2
+
+ people = [
+ ('Andrew', 'Sumner', 'Andy'), #1
+ ('Peter', 'Seattle', None), #2
+ ('Susan', 'Boston', 'Beannie'), #3
+ ('Pam', 'Coventry', 'PJ'), #4
+ ('Steven', 'Colchester', None), #5
+ ]
+
+ logger.info('Creating Person records: iterate through the list of tuples')
+ logger.info('Prepare to explain any errors with exceptions')
+ logger.info('and the transaction tells the database to fail on error')
+
+ try:
+ database.connect()
+ database.execute_sql('PRAGMA foreign_keys = ON;')
+ for person in people:
+ with database.transaction():
+ new_person = Person.create(
+ person_name = person[PERSON_NAME],
+ lives_in_town = person[LIVES_IN_TOWN],
+ nickname = person[NICKNAME])
+ new_person.save()
+ logger.info('Database add successful')
+
+ logger.info('Print the Person records we saved...')
+ for saved_person in Person:
+ logger.info(f'{saved_person.person_name} lives in {saved_person.lives_in_town} ' +\
+ f'and likes to be known as {saved_person.nickname}')
+
+ except Exception as e:
+ logger.info(f'Error creating = {person[PERSON_NAME]}')
+ logger.info(e)
+ logger.info('See how the database protects our data')
+
+ finally:
+ logger.info('database closes')
+ database.close()
+
+def populate_department():
+ """
+ add person data to database
+ """
+
+ logging.basicConfig(level=logging.INFO)
+ logger = logging.getLogger(__name__)
+
+ database = SqliteDatabase('personjob.db')
+
+ logger.info('Working with Department class')
+ logger.info('Note how I use constants and a list of tuples as a simple schema')
+ logger.info('Normally you probably will have prompted for this from a user')
+
+ DEPT_CODE = 0
+ DEPT_NAME = 1
+ MANAGER = 2
+
+ departments = [
+ ('W301', 'Finance', 'Willy Wonka'), #1
+ ('R501', 'Human Resources', 'Charlie Bucket' ), #2
+ ('L200', 'Logistics', 'Augustus Gloop'), #3
+ ('M729', 'Information Technology', 'Veruca Salt'), #4
+ ('Y782', 'Business Development', 'Mike Teavee'), #5
+ ]
+
+ logger.info('Creating Department records: iterate through the list of tuples')
+ logger.info('Prepare to explain any errors with exceptions')
+ logger.info('and the transaction tells the database to fail on error')
+
+ try:
+ database.connect()
+ database.execute_sql('PRAGMA foreign_keys = ON;')
+ for dept in departments:
+ with database.transaction():
+ new_dept = Department.create(
+ department_code = dept[DEPT_CODE],
+ department_name = dept[DEPT_NAME],
+ manager = dept[MANAGER])
+ new_dept.save()
+ logger.info('Database add successful')
+
+ logger.info('Print the Person records we saved...')
+ for saved_person in Person:
+ logger.info(f'{saved_person.person_name} lives in {saved_person.lives_in_town} ' +\
+ f'and likes to be known as {saved_person.nickname}')
+
+ except Exception as e:
+ logger.info(f'Error creating = {dept[DEPT_NAME]}')
+ logger.info(e)
+ logger.info('See how the database protects our data')
+
+ finally:
+ logger.info('database closes')
+ database.close()
+
+def populate_job():
+ """
+ add job data to database
+ """
+
+ logging.basicConfig(level=logging.INFO)
+ logger = logging.getLogger(__name__)
+
+ database = SqliteDatabase('personjob.db')
+
+ logger.info('Working with Job class')
+ logger.info('Creating Job records: just like Person. We use the foreign key')
+
+ JOB_NAME = 0
+ START_DATE = 1
+ END_DATE = 2
+ SALARY = 3
+ PERSON_ID = 4
+ DEPT_ID = 5
+
+
+ jobs = [
+ ('Analyst', '2001-09-22', '2003-01-30',65500, 1, 3),
+ ('Senior analyst', '2003-02-01', '2006-10-22', 70000, 1, 2),
+ ('Senior business analyst', '2006-10-23', '2016-12-24', 80000, 1, 1),
+ ('Admin supervisor', '2012-10-01', '2014-11-10', 45900, 2, 2),
+ ('Admin manager', '2014-11-14', '2018-01-05', 45900, 5, 4)
+ ]
+
+ try:
+ database.connect()
+ database.execute_sql('PRAGMA foreign_keys = ON;')
+ for job in jobs:
+ with database.transaction():
+ new_job = Job.create(
+ job_name = job[JOB_NAME],
+ start_date = job[START_DATE],
+ end_date = job[END_DATE],
+ salary = job[SALARY],
+ person_id = job[PERSON_ID],
+ dept_id = job[DEPT_ID])
+ new_job.save()
+
+ logger.info('Reading and print all Job rows (note the value of person)...')
+ for job in Job:
+ logger.info(f'{job.job_name}: {job.start_date} to {job.end_date} for {job.person_id}')
+
+ except Exception as e:
+ logger.info(f'Error creating = {job[JOB_NAME]}')
+ logger.info(e)
+
+ finally:
+ logger.info('database closes')
+ database.close()
+
+if __name__ == '__main__':
+ populate_person()
+ populate_department()
+ populate_job()
\ No newline at end of file
diff --git a/Student/stephen/lesson07/lesson07_activity/query_db.py b/Student/stephen/lesson07/lesson07_activity/query_db.py
new file mode 100644
index 0000000..7dfdc28
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_activity/query_db.py
@@ -0,0 +1,52 @@
+"""
+Module for querying exercise from lesson 7 activity:
+We also need to know the duration in days that the job was held.
+Produce a list using pretty print that shows all of the departments a person worked in for every job they ever had.
+"""
+
+from personjob_model import *
+
+import logging
+import pprint as pp
+from datetime import date
+
+
+def join_classes():
+ """
+ demonstrate how to join classes together : no matches too
+ """
+
+ logging.basicConfig(level=logging.CRITICAL)
+ logger = logging.getLogger(__name__)
+
+ database = SqliteDatabase('personjob.db')
+
+ logger.info("View records of people's jobs, how many days they had them and the department they were in")
+
+ try:
+ database.connect()
+ database.execute_sql('PRAGMA foreign_keys = ON;')
+ logger.info("Querying the database")
+ query = (Job
+ .select(Person.person_name.alias('Name'), Job.job_name.alias('Job Title'), Department.department_name.alias('Department'), Job.days_on_job.alias('Days'))
+ .join(Person, JOIN.INNER)
+ .switch(Job)
+ .join(Department, JOIN.INNER)
+ .dicts() # used this feature to setup the output for pretty print
+ )
+
+ for person in query:
+ try:
+ pp.pprint(person)
+
+ except Exception as e:
+ logger.info(e)
+
+ except Exception as e:
+ logger.info(e)
+
+ finally:
+ database.close()
+
+if __name__ == '__main__':
+ join_classes()
diff --git a/Student/stephen/lesson07/lesson07_assignment/Elmer_Fudd.txt b/Student/stephen/lesson07/lesson07_assignment/Elmer_Fudd.txt
new file mode 100644
index 0000000..f28ec1e
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_assignment/Elmer_Fudd.txt
@@ -0,0 +1,6 @@
+Dear Elmer Fudd,
+
+We greatly appreciate your generous donation of $99.99.
+
+Thank you,
+The Team
\ No newline at end of file
diff --git a/Student/stephen/lesson07/lesson07_assignment/Elon_Musk.txt b/Student/stephen/lesson07/lesson07_assignment/Elon_Musk.txt
new file mode 100644
index 0000000..dcdbb26
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_assignment/Elon_Musk.txt
@@ -0,0 +1,6 @@
+Dear Elon Musk,
+
+We greatly appreciate your generous donation of $150.00.
+
+Thank you,
+The Team
\ No newline at end of file
diff --git a/Student/stephen/lesson07/lesson07_assignment/Jeff_Bezos.txt b/Student/stephen/lesson07/lesson07_assignment/Jeff_Bezos.txt
new file mode 100644
index 0000000..69053a5
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_assignment/Jeff_Bezos.txt
@@ -0,0 +1,6 @@
+Dear Jeff Bezos,
+
+We greatly appreciate your generous donation of $100.00.
+
+Thank you,
+The Team
\ No newline at end of file
diff --git a/Student/stephen/lesson07/lesson07_assignment/Oprah_Winfrey.txt b/Student/stephen/lesson07/lesson07_assignment/Oprah_Winfrey.txt
new file mode 100644
index 0000000..d92adfc
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_assignment/Oprah_Winfrey.txt
@@ -0,0 +1,6 @@
+Dear Oprah Winfrey,
+
+We greatly appreciate your generous donation of $200.00.
+
+Thank you,
+The Team
\ No newline at end of file
diff --git a/Student/stephen/lesson07/lesson07_assignment/Paul_Allen.txt b/Student/stephen/lesson07/lesson07_assignment/Paul_Allen.txt
new file mode 100644
index 0000000..183af9d
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_assignment/Paul_Allen.txt
@@ -0,0 +1,6 @@
+Dear Paul Allen,
+
+We greatly appreciate your generous donation of $75.00.
+
+Thank you,
+The Team
\ No newline at end of file
diff --git a/Student/stephen/lesson07/lesson07_assignment/Richard_Branson.txt b/Student/stephen/lesson07/lesson07_assignment/Richard_Branson.txt
new file mode 100644
index 0000000..6fca06c
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_assignment/Richard_Branson.txt
@@ -0,0 +1,6 @@
+Dear Richard Branson,
+
+We greatly appreciate your generous donation of $90.00.
+
+Thank you,
+The Team
\ No newline at end of file
diff --git a/Student/stephen/lesson07/lesson07_assignment/__pycache__/donor_model.cpython-36.pyc b/Student/stephen/lesson07/lesson07_assignment/__pycache__/donor_model.cpython-36.pyc
new file mode 100644
index 0000000..86ccf7e
Binary files /dev/null and b/Student/stephen/lesson07/lesson07_assignment/__pycache__/donor_model.cpython-36.pyc differ
diff --git a/Student/stephen/lesson07/lesson07_assignment/__pycache__/donor_report.cpython-36.pyc b/Student/stephen/lesson07/lesson07_assignment/__pycache__/donor_report.cpython-36.pyc
new file mode 100644
index 0000000..89ee7e8
Binary files /dev/null and b/Student/stephen/lesson07/lesson07_assignment/__pycache__/donor_report.cpython-36.pyc differ
diff --git a/Student/stephen/lesson07/lesson07_assignment/donor_db.db b/Student/stephen/lesson07/lesson07_assignment/donor_db.db
new file mode 100644
index 0000000..87bc77e
Binary files /dev/null and b/Student/stephen/lesson07/lesson07_assignment/donor_db.db differ
diff --git a/Student/stephen/lesson07/lesson07_assignment/donor_model.py b/Student/stephen/lesson07/lesson07_assignment/donor_model.py
new file mode 100644
index 0000000..97f152d
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_assignment/donor_model.py
@@ -0,0 +1,63 @@
+"""
+ This is a simple database model to house data
+ for the Mailroom Application. The model
+ just has two tables: Donor and Donation related
+ by a donor_id field in Donation that references
+ Donor
+"""
+
+from peewee import Model, CharField, DateTimeField, JOIN, fn, DoesNotExist
+from peewee import DecimalField, ForeignKeyField, SqliteDatabase
+from datetime import date, datetime, time
+# need this library for hybrid properties
+from playhouse.hybrid import hybrid_method, hybrid_property
+
+database = SqliteDatabase('donor_db.db')
+database.connect()
+
+database.execute_sql('PRAGMA foreign_keys = ON;')
+
+class BaseModel(Model):
+ class Meta:
+ database = database
+
+class Donor(BaseModel):
+ """
+ This class defines the Donor, which maintains details of someone
+ who has made a donation to the organization. We'll be using the auto
+ generated primary keys since we may have people with the same name
+ who donate
+ """
+ first_name = CharField(max_length=50)
+ middle_name = CharField(max_length=50, null=True)
+ last_name = CharField(max_length=50)
+ preferred_name = CharField(max_length=100, null=True)
+ address = CharField(max_length=100, null=True)
+ city = CharField(max_length=50, null=True)
+ state = CharField(max_length=50, null=True) # in case of out of country
+ zip_code = CharField(max_length=20, null=True)
+ email = CharField(max_length=100)
+ phone = CharField(max_length=25)
+
+class Donation(BaseModel):
+ """
+ This class defines Donations, which maintains details about how
+ much donors contribute to the organization
+ """
+ donor_id = ForeignKeyField(Donor, null=False)
+ amount = DecimalField(max_digits=11, decimal_places=2)
+ donation_dt = DateTimeField()
+ # Note to self: by default datetimefield formatted as YYYY-MM-DD HH:MM:SS
+
+if __name__ == '__main__':
+ # Drop tables to start with a clean slate
+ database.execute_sql('DROP TABLE IF EXISTS Donation;')
+ database.execute_sql('DROP TABLE IF EXISTS Donor;')
+
+ # Create tables
+ database.create_tables([
+ Donor,
+ Donation
+ ])
+
+ database.close()
\ No newline at end of file
diff --git a/Student/stephen/lesson07/lesson07_assignment/donor_report.py b/Student/stephen/lesson07/lesson07_assignment/donor_report.py
new file mode 100644
index 0000000..d97686d
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_assignment/donor_report.py
@@ -0,0 +1,34 @@
+"""
+Module for creating a report
+"""
+
+from donor_model import *
+
+def create_report():
+ """
+ Creates report print-out
+ """
+ donor_donations = (
+ Donation.select(
+ Donation.donor_id,
+ Donor.first_name,
+ Donor.last_name,
+ fn.SUM(Donation.amount).alias('total_given'),
+ fn.COUNT(Donation.id).alias('num_gifts'),
+ fn.AVG(Donation.amount).alias('average_gift')
+ )
+ .join(Donor, JOIN.INNER)
+ .group_by(Donation.donor_id, Donor.first_name, Donor.last_name)
+ .order_by(fn.SUM(Donation.amount).desc())
+ )
+
+ report_rows = []
+ for d in donor_donations:
+ name = d.donor_id.first_name + ' ' + d.donor_id.last_name
+ report_rows.append('{:26s} {:>12s} {:^13d} {:>12s}'.format(name, '${:,.2f}'.format(d.total_given), d.num_gifts, '${:,.2f}'.format(d.average_gift)))
+ header = ('Donor Name | Total Given | Num Gifts | Average Gift\n') + ('-' * 66) + '\n'
+ return header + '\n'.join(report_rows) + '\n'
+
+if __name__ == '__main__':
+ print(create_report())
+ database.close()
\ No newline at end of file
diff --git a/Student/stephen/lesson07/lesson07_assignment/lesson07_assignment.zip b/Student/stephen/lesson07/lesson07_assignment/lesson07_assignment.zip
new file mode 100644
index 0000000..2a8b1e3
Binary files /dev/null and b/Student/stephen/lesson07/lesson07_assignment/lesson07_assignment.zip differ
diff --git a/Student/stephen/lesson07/lesson07_assignment/mailroom_rdbms.py b/Student/stephen/lesson07/lesson07_assignment/mailroom_rdbms.py
new file mode 100644
index 0000000..1be2a3a
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_assignment/mailroom_rdbms.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python
+
+"""
+Simple Mailroom Program for a nonprofit
+Using RDBMS model to persist data
+"""
+
+# The script should prompt the user (you) to choose from a menu of 3 actions:
+# “Send a Thank You”, “Create a Report” or “quit”)
+
+import os, sys
+import json
+from donor_model import *
+from donor_report import create_report
+
+database = SqliteDatabase('donor_db.db')
+database.connect()
+database.execute_sql('PRAGMA foreign_keys = ON;')
+
+class aDonor:
+ """
+ Handles the donor
+ """
+ def __init__(self, donor_id):
+ self._donor_id = donor_id
+ self._donor_info = Donor.get(Donor.id == self._donor_id)
+ self._name = self._donor_info.first_name + ' ' + self._donor_info.last_name
+ self._donation_info = (
+ Donation.select(
+ Donation.donor_id,
+ fn.SUM(Donation.amount).alias('total_given'),
+ fn.COUNT(Donation.id).alias('num_gifts'),
+ fn.AVG(Donation.amount).alias('average_gift'),
+ fn.MAX(Donation.donation_dt).alias('last_gift_dt')
+ )
+ .join(Donor, JOIN.INNER)
+ .where(Donation.donor_id == self._donor_id)
+ .group_by(Donation.donor_id)
+ .order_by(fn.SUM(Donation.amount).desc())
+ .limit(1)
+ .get()
+ )
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def donations(self):
+ query = (Donation.select(Donation.donation_dt, Donation.amount)
+ .where(Donation.donor_id == self._donor_id)
+ .order_by(Donation.donation_dt.desc()))
+ donations_list = []
+ for row in query:
+ donations_list.append((row.donation_dt.strftime("%m-%d-%Y"), '${:,.2f}'.format(row.amount)))
+ self._donations = donations_list
+ return self._donations
+
+ def add_donation(self, donation, dt=datetime.now()):
+ self._donation = donation
+ try:
+ with database.transaction():
+ new_donation = Donation.create(
+ donor_id = self._donor_id,
+ amount = self._donation,
+ donation_dt = dt
+ )
+ new_donation.save()
+ except Exception as e:
+ """
+ If I had more time I would figure out how to make the
+ program recover more gracefully from exceptions
+ """
+ raise(e)
+
+ @property
+ def total_donations(self):
+ return self._donation_info.total_given
+ # return reduce(lambda a, x: a+x, self._donations, 0)
+ # s = 0
+ # for d in donations:
+ # s += d
+ # return s
+
+ @property
+ def count_donations(self):
+ return self._donation_info.num_gifts
+
+ @property
+ def average_donation(self):
+ return self._donation_info.average_gift
+
+ @property
+ def letter(self):
+ """
+ Takes the donor and returns a string that is a formatted thank you note
+ with the donor's name and last donation amount.
+ """
+ last_donation = (Donation.select(Donation.amount)
+ .where(Donation.donor_id == self._donor_id)
+ .order_by(Donation.id.desc())
+ .limit(1)
+ .get()
+ )
+ return "Dear {:s},\n\nWe greatly appreciate your generous donation of ${:,.2f}.\n\nThank you,\nThe Team".format(self._name, last_donation.amount)
+
+ @property
+ def filename(self):
+ 'Return a txt file name based on the donor name and using underscores instead of spaces'
+ return self._name.replace(' ', '_') + '.txt'
+
+ # allow other items to call the class
+ def __repr__(self):
+ return "{}: {}".format(self._name, self._donations)
+
+class Menu:
+ response = None
+
+ def __init__(self, title, menu):
+ self._title = title
+ self._menu = menu
+ error_msg = 'Not a valid response. Enter '
+ for key in self._menu:
+ error_msg += key + ', '
+ self._error = error_msg[:-3] + 'or ' + error_msg[-3] + '.\n'
+
+ def menu(self):
+ m = [str(k) + ') ' + str(v[0]) + '\n' for k, v in self._menu.items()]
+ return ''.join(m)
+
+ def get_response(self):
+ print(self._title)
+ print(self.menu())
+ response = input('>> ')
+ while response not in self._menu:
+ print(self._error)
+ response = input('>> ')
+ self.response = response
+
+ @property
+ def switch(self):
+ return {k:v[1] for k, v in self._menu.items()}
+
+def print_report():
+ print(create_report())
+
+def return_to_main():
+ return
+
+def write_letters_to_disk():
+ """
+ Generate one letter for each donor and write to disk
+ """
+ query = (
+ Donor.select(Donor.id)
+ .join(Donation, JOIN.INNER)
+ .group_by(Donor.id)
+ )
+ for row in query:
+ donor = aDonor(row.id)
+ print('Generating letter to {:s}'.format(donor.name))
+ with open(donor.filename, 'w') as outfile:
+ outfile.write(donor.letter)
+ print()
+ return
+
+def enter_donor_info():
+ print('\nEnter the first name of the donor')
+ e_first_name = input('>> ')
+ print('Optional: Enter the middle name of the donor')
+ e_middle_name = input('>> ')
+ print('Enter the last name of the donor')
+ e_last_name = input('>> ')
+ print('Optional: Enter the preferred name of the donor')
+ e_preferred_name = input('>> ')
+ print('Optional: Enter the street address of the donor')
+ e_address = input('>> ')
+ print('Optional: Enter the donor city')
+ e_city = input('>> ')
+ print('Optional: Enter the donor state')
+ e_state = input('>> ')
+ print('Optional: Enter the donor zip code')
+ e_zip_code = input('>> ')
+ print('Enter the donor email address')
+ e_email = input('>> ')
+ print('Enter the donor phone number')
+ e_phone = input('>> ')
+ print('Enter the donation amount')
+ e_amount = input('>> ')
+ print()
+ try:
+ with database.transaction():
+ new_donor = Donor.create(
+ first_name = e_first_name,
+ middle_name = e_middle_name,
+ last_name = e_last_name,
+ preferred_name = e_preferred_name,
+ address = e_address,
+ city = e_city,
+ state = e_state,
+ zip_code = e_zip_code,
+ email = e_email,
+ phone = e_phone
+ )
+ new_donor.save()
+
+ new_donation = Donation.create(
+ donor_id = new_donor.id,
+ amount = e_amount,
+ donation_dt = datetime.now()
+ )
+ new_donation.save()
+
+ print(aDonor(new_donor.id).letter)
+ print()
+
+ except Exception as e:
+ """
+ If I had more time I would figure out how to make the
+ program recover more gracefully from exceptions
+ """
+ raise(e)
+
+ return
+
+def enter_donation():
+ """
+ If i had more time I would try to handle cases
+ where two donors exist with the same first
+ and last names
+ """
+ print('\nEnter the first name of the donor')
+ e_first_name = input('>> ')
+ print('Enter the last name of the donor')
+ e_last_name = input('>> ')
+ try:
+ donor = Donor.get(Donor.first_name == e_first_name and Donor.last_name == e_last_name)
+ except DoesNotExist:
+ print('The donor could not be found')
+ print()
+ return
+ print('Enter the donation amount')
+ e_amount = input('>> ')
+ print('Enter the date of the donation (using mm/dd/yyyy fromat, ex: 06/30/2018)')
+ e_donation_date = input('>> ')
+ current_donor = aDonor(donor.id)
+ current_donor.add_donation(e_amount, dt=e_donation_date)
+ print()
+ print(current_donor.letter)
+ print()
+ return
+
+def print_donor_list():
+ print('\nDonors:')
+ query = Donor.select(Donor.id)
+ for row in query:
+ donor = aDonor(row.id)
+ print(donor.name)
+ print()
+ pass
+
+def thank_you():
+ ty = Menu('Thank You Menu:', thank_you_menu)
+ ty.get_response()
+ ty.switch.get(ty.response)()
+ return
+
+def quit_program():
+ """
+ Close database connection
+ """
+ database.close()
+ sys.exit()
+
+main_menu = {
+ '1': ['Send a Thank You', thank_you]
+ , '2': ['Create a Report', print_report]
+ , '3': ['Send letters to everyone', write_letters_to_disk]
+ , '4': ['Quit', quit_program]
+ }
+
+thank_you_menu = {
+ '1': ['Add a new donor', enter_donor_info]
+ , '2': ['Enter a donation for an existing donor', enter_donation]
+ , '3': ['See a list of donor names', print_donor_list]
+ , '4': ['Return to the Main Menu', return_to_main]
+ }
+
+def mainloop():
+ print('Welcome to Mailroom\n')
+ main = Menu('Main Menu:', main_menu)
+ while True:
+ main.get_response()
+ main.switch.get(main.response)()
+
+if __name__ == '__main__':
+ mainloop()
diff --git a/Student/stephen/lesson07/lesson07_assignment/populate_donor_db.py b/Student/stephen/lesson07/lesson07_assignment/populate_donor_db.py
new file mode 100644
index 0000000..4ee33a1
--- /dev/null
+++ b/Student/stephen/lesson07/lesson07_assignment/populate_donor_db.py
@@ -0,0 +1,119 @@
+"""
+ This module creates and does an initial population
+ of the donor database.
+"""
+
+from donor_model import *
+
+def populate_donor():
+ """
+ Add initial donors to the database
+ """
+
+ database = SqliteDatabase('donor_db.db')
+
+ FIRST_NAME = 0
+ MIDDLE_NAME = 1
+ LAST_NAME = 2
+ PREFERRED_NAME = 3
+ ADDRESS = 4
+ CITY = 5
+ STATE = 6
+ ZIP_CODE = 7
+ EMAIL = 8
+ PHONE = 9
+
+ donors = [
+ ('Jeff', None, 'Bezos', None, '345 15th Ave', 'Medina', 'WA', '98045', 'jeff@amazon.com', '206-555-9898'), #1
+ ('Paul', 'C', 'Allen', None, '9753 Main St', 'Bellevue', 'WA', '98025', 'pallen@email.com', '425-989-5555'), #2
+ ('Oprah', None, 'Winfrey', None, '178 Robin Lane', 'Orcas Island', 'WA', '98478', 'oprah@ownetwork.com', '800-678-3333'), #3
+ ('Elon', None, 'Musk', None, '900 Rialto St', 'San Francisco', 'CA', '94129', 'elon@tesla.com', '615-309-5928'), #4
+ ('Richard', 'Charles', 'Branson', 'Rich', '516 Abbey Rd', 'New York City', 'NY', '10007', 'richard@virgin.com', '888-907-1859'), #5
+ ]
+
+ try:
+ database.connect()
+ database.execute_sql('PRAGMA foreign_keys = ON;')
+ for donor in donors:
+ with database.transaction():
+ new_donor = Donor.create(
+ first_name = donor[FIRST_NAME],
+ middle_name = donor[MIDDLE_NAME],
+ last_name = donor[LAST_NAME],
+ preferred_name = donor[PREFERRED_NAME],
+ address = donor[ADDRESS],
+ city = donor[CITY],
+ state = donor[STATE],
+ zip_code = donor[ZIP_CODE],
+ email = donor[EMAIL],
+ phone = donor[PHONE]
+ )
+ new_donor.save()
+
+ # print out donors that have been saved
+ for saved_donor in Donor:
+ print(f'{saved_donor.first_name} {saved_donor.last_name} lives in {saved_donor.city}, {saved_donor.state}')
+
+ except Exception as e:
+ print(f'Error creating = {donor[FIRST_NAME]} {donor[LAST_NAME]}')
+ raise(e)
+
+ finally:
+ database.close()
+
+def populate_donation():
+ """
+ Add initial donations to the database
+ """
+
+ database = SqliteDatabase('donor_db.db')
+
+ DONOR_ID = 0
+ AMOUNT = 1
+ DONATION_DT = 2
+
+ donations = [
+ (1, 100.00, '2018-01-02'), #1
+ (1, 75.00, '2018-02-20'), #2
+ (2, 500.00, '2018-04-15'), #3
+ (2, 75, '2018-05-01'), #4
+ (3, 200, '2018-05-01'), #5
+ (4, 150.00, '2018-05-02'), #6
+ (5, 600.00, '2018-05-13'), #7
+ (5, 90.00, '2018-06-01'), #8
+ (1, 100.00, datetime.now()), #9
+ ]
+
+ try:
+ database.connect()
+ database.execute_sql('PRAGMA foreign_keys = ON;')
+ for donation in donations:
+ with database.transaction():
+ new_donation = Donation.create(
+ donor_id = donation[DONOR_ID],
+ amount = donation[AMOUNT],
+ donation_dt = donation[DONATION_DT]
+ )
+ new_donation.save()
+
+ # print out donor donations
+ donor_donations = (
+ Donation.select(Donor.first_name, Donor.last_name, Donation.amount, Donation.donation_dt)
+ .join(Donor, JOIN.INNER)
+ )
+
+ for donor_donation in donor_donations:
+ donation_date = donor_donation.donation_dt.strftime("%B %d, %Y")
+ print(f'{donor_donation.donor_id.first_name} {donor_donation.donor_id.last_name}',
+ f'donated ${donor_donation.amount} on {donation_date}.')
+
+ except Exception as e:
+ print(f'Error creating = {donation[DONOR_ID]} {donation[AMOUNT]} {donation[DONATION_DT]}')
+ raise(e)
+
+ finally:
+ database.close()
+
+if __name__ == '__main__':
+ populate_donor()
+ populate_donation()
\ No newline at end of file
diff --git a/Student/stephen/lesson08/lesson08_activity/lesson08_activity.zip b/Student/stephen/lesson08/lesson08_activity/lesson08_activity.zip
new file mode 100644
index 0000000..edcee62
Binary files /dev/null and b/Student/stephen/lesson08/lesson08_activity/lesson08_activity.zip differ
diff --git a/Student/stephen/lesson08/lesson08_activity/nosql b/Student/stephen/lesson08/lesson08_activity/nosql
new file mode 160000
index 0000000..47bcf7f
--- /dev/null
+++ b/Student/stephen/lesson08/lesson08_activity/nosql
@@ -0,0 +1 @@
+Subproject commit 47bcf7f208f28533b037fb6207fbdf58f9fb8c35
diff --git a/Student/stephen/lesson09/lesson09_actviity/lesson09_activity.py b/Student/stephen/lesson09/lesson09_actviity/lesson09_activity.py
new file mode 100644
index 0000000..c02da8a
--- /dev/null
+++ b/Student/stephen/lesson09/lesson09_actviity/lesson09_activity.py
@@ -0,0 +1,27 @@
+import threading
+import time
+import random
+
+# simple threading
+def func(n):
+ for i in range(n):
+ print('hello from thread %s' % threading.current_thread().name)
+ time.sleep(random.random() * 2)
+
+
+threads = []
+for i in range(3):
+ thread = threading.Thread(target=func, args=(i + 4,))
+ thread.start()
+ threads.append(thread)
+
+# threads are not "blocking" eachother
+
+# this code starts blocking the threads
+for thread in threads:
+ print("joining thread: ", thread.name)
+ thread.join()
+
+# this code is blocked before running
+print("all threads finished")
+# makes sure all the threads are finished before executing
\ No newline at end of file
diff --git a/Student/stephen/lesson09/lesson09_actviity/lesson09_activity.zip b/Student/stephen/lesson09/lesson09_actviity/lesson09_activity.zip
new file mode 100644
index 0000000..b769e27
Binary files /dev/null and b/Student/stephen/lesson09/lesson09_actviity/lesson09_activity.zip differ
diff --git a/Student/stephen/lesson09/lesson09_actviity/lesson09_activity2.py b/Student/stephen/lesson09/lesson09_actviity/lesson09_activity2.py
new file mode 100644
index 0000000..5eeffa3
--- /dev/null
+++ b/Student/stephen/lesson09/lesson09_actviity/lesson09_activity2.py
@@ -0,0 +1,26 @@
+import threading
+import time
+
+# create a mutable object that is shared among threads
+class shared:
+ val = 1
+
+def func():
+ y = shared.val
+ time.sleep(.1)
+ y += 1
+ shared.val = y
+
+threads = []
+# with enough threads, there's sufficient overhead to
+# cause a race condition
+
+for i in range(100):
+ thread = threading.Thread(target=func)
+ threads.append(thread)
+ thread.start()
+
+for thread in threads:
+ thread.join()
+
+print(shared.val)
\ No newline at end of file
diff --git a/Student/stephen/lesson09/lesson09_actviity/lesson09_activity3.py b/Student/stephen/lesson09/lesson09_actviity/lesson09_activity3.py
new file mode 100644
index 0000000..5eeffa3
--- /dev/null
+++ b/Student/stephen/lesson09/lesson09_actviity/lesson09_activity3.py
@@ -0,0 +1,26 @@
+import threading
+import time
+
+# create a mutable object that is shared among threads
+class shared:
+ val = 1
+
+def func():
+ y = shared.val
+ time.sleep(.1)
+ y += 1
+ shared.val = y
+
+threads = []
+# with enough threads, there's sufficient overhead to
+# cause a race condition
+
+for i in range(100):
+ thread = threading.Thread(target=func)
+ threads.append(thread)
+ thread.start()
+
+for thread in threads:
+ thread.join()
+
+print(shared.val)
\ No newline at end of file
diff --git a/Student/stephen/lesson09/lesson09_actviity/multithread_api_example.py b/Student/stephen/lesson09/lesson09_actviity/multithread_api_example.py
new file mode 100644
index 0000000..5ec9949
--- /dev/null
+++ b/Student/stephen/lesson09/lesson09_actviity/multithread_api_example.py
@@ -0,0 +1,19 @@
+import requests
+import threading
+import json
+from math import ceil
+import sqlite3
+
+api_key = '0b8b3765b41643e69374333bb63a4d5a'
+keywords = ','.join(['Amazon', 'Bezos'])
+page = 1
+url = (f'https://newsapi.org/v2/everything?'
+ 'q={keywords}&'
+ 'from=2018-06-21&'
+ 'sortBy=popularity&'
+ 'apiKey={api_key}&'
+ 'page={page}')
+
+url = url.format(keywords=keywords, page=page, api_key=api_key)
+print(url)
+
diff --git a/Student/stephen/lesson09/lesson09_assignment/async_webscraper.py b/Student/stephen/lesson09/lesson09_assignment/async_webscraper.py
new file mode 100644
index 0000000..31bf1d9
--- /dev/null
+++ b/Student/stephen/lesson09/lesson09_assignment/async_webscraper.py
@@ -0,0 +1,83 @@
+import time
+import asyncio
+import aiohttp
+# import request
+
+NEWS_API_KEY = '0b8b3765b41643e69374333bb63a4d5a'
+
+WORD = 'trump'
+
+base_url = 'https://newsapi.org/v1/'
+
+# use one session for the whoe script
+# recommended by the docs
+# sesson = aiohttp.ClientSession()
+
+# this has to run first, so doesn't really need async
+async def get_sources(sources):
+ """
+ Get all the english language sources of news
+ 'https://newsapi.org/v1/sources?language=en'
+ """
+ url = base_url + "sources"
+ params = {"language": "en"}
+ sesson = aiohttp.ClientSession()
+ async with aiohttp.ClientSession() as session:
+ async with session.get(url, ssl=False, params=params) as resp:
+ data = await resp.json()
+ print("Got the sources")
+ sources.extend([src['id'].strip() for src in data['sources']])
+
+async def get_articles(source):
+ """
+ https://newsapi.org/v1/articles?source=associated-press
+ """
+ url = base_url + "articles"
+ params = {"source": source,
+ "apiKey": NEWS_API_KEY,
+ "sortBy": "top"
+ }
+ print("requesting:", source)
+ async with aiohttp.ClientSession() as session:
+ async with session.get(url, ssl=False, params=params) as resp:
+ if resp.status != 200: # aiohttpp has "status"
+ print("something went wront with: {}".format(source))
+ await asyncio.sleep(0)
+ return
+ data = await resp.json()
+ print("got the articles from {}".format(source))
+ # the url to the article itself is in data['articles'][i]['url']
+ titles.extend([str(art['title']) + str(art['description'])
+ for art in data['articles']])
+
+def count_word(word, titles):
+ word = word.lower()
+ count = 0
+ for title in titles:
+ if word in title.lower():
+ count += 1
+ return count
+
+start = time.time()
+
+# start up a loop:
+loop = asyncio.get_event_loop()
+
+# create the objects to hold the data
+sources = []
+titles = []
+
+# get the sources -- this is essentially synchronous
+loop.run_until_complete(get_sources(sources))
+
+# running the loop for the articles
+jobs = asyncio.gather(*(get_articles(source) for source in sources))
+loop.run_until_complete(jobs)
+loop.close()
+# session.close()
+
+art_count = len(titles)
+word_count = count_word(WORD, titles)
+
+print(WORD, "found {} times in {} articles".format(word_count, art_count))
+print("Process took {:.0f} seconds".format(time.time() - start))
\ No newline at end of file
diff --git a/Student/stephen/lesson09/lesson09_assignment/lesson09_assgnment.zip b/Student/stephen/lesson09/lesson09_assignment/lesson09_assgnment.zip
new file mode 100644
index 0000000..e2871a4
Binary files /dev/null and b/Student/stephen/lesson09/lesson09_assignment/lesson09_assgnment.zip differ
diff --git a/Student/stephen/lesson09/lesson09_assignment/simple_webscraper.py b/Student/stephen/lesson09/lesson09_assignment/simple_webscraper.py
new file mode 100644
index 0000000..0bebb9a
--- /dev/null
+++ b/Student/stephen/lesson09/lesson09_assignment/simple_webscraper.py
@@ -0,0 +1,65 @@
+import time
+import requests
+
+NEWS_API_KEY = '0b8b3765b41643e69374333bb63a4d5a'
+
+WORD = 'trump'
+
+base_url = 'https://newsapi.org/v1/'
+
+def get_sources():
+ """
+ Get all the english language sources of news
+ 'https://newsapi.org/v1/sources?language=en'
+ """
+ url = base_url + "sources"
+ params = {"language": "en"}
+ resp = requests.get(url, params=params)
+ data = resp.json()
+ sources = [src['id'].strip() for src in data['sources']]
+ print("all the sources")
+ print(sources)
+ return sources
+
+def get_articles(source):
+ """
+ https://newsapi.org/v1/articles?source=associated-press
+ """
+ url = base_url + "articles"
+ params = {"source": source,
+ "apiKey": NEWS_API_KEY,
+ "sortBy": "top"
+ }
+ print("requesting:", source)
+ resp = requests.get(url, params=params)
+ if resp.status_code != 200:
+ print("something went wrong with {}".format(source))
+ print(resp)
+ print(resp.text)
+ return []
+ data = resp.json()
+ # the url to the article itself is in data['articles'][i]['url']
+ titles = [str(art['title']) + str(art['description'])
+ for art in data['articles']]
+ return titles
+
+def count_word(word, titles):
+ word = word.lower()
+ count = 0
+ for title in titles:
+ if word in title.lower():
+ count += 1
+ return count
+
+start = time.time()
+sources = get_sources()
+
+art_count = 0
+word_count = 0
+for source in sources:
+ titles = get_articles(source)
+ art_count += len(titles)
+ word_count += count_word(WORD, titles)
+
+print(WORD, "found {} times in {} articles".format(word_count, art_count))
+print("Process took {:.0f} seconds".format(time.time() - start))
\ No newline at end of file
diff --git a/Student/stephen/lesson09/lesson09_assignment/threaded_webscraper.py b/Student/stephen/lesson09/lesson09_assignment/threaded_webscraper.py
new file mode 100644
index 0000000..c8143b3
--- /dev/null
+++ b/Student/stephen/lesson09/lesson09_assignment/threaded_webscraper.py
@@ -0,0 +1,83 @@
+"""
+Attempt at threaded approach to news webscraper. I kept running into this
+error {"status":"error","code":"rateLimited","message":"You have made too many requests recently. Developer accounts are limited to 1,000 requests over a 24 hour period (250 requests available every 6 hours). Please upgrade to a paid plan if you need more requests."}
+"""
+import time
+import requests
+import threading
+
+NEWS_API_KEY = 'ebb338c04b1c416ba9ea2ab24f5c0fa6'#'fa5580717eab48e3bca211c82602c5c4'#'0b8b3765b41643e69374333bb63a4d5a'
+
+WORD = 'trump'
+
+base_url = 'https://newsapi.org/v1/'
+
+max_threads = 10
+
+def get_sources():
+ """
+ Get all the english language sources of news
+ 'https://newsapi.org/v1/sources?language=en'
+ """
+ url = base_url + "sources"
+ params = {"language": "en"}
+ resp = requests.get(url, params=params)
+ data = resp.json()
+ sources = [src['id'].strip() for src in data['sources']]
+ print("all the sources")
+ print(sources)
+ return sources
+
+
+art_count = 0
+word_count = 0
+
+def get_articles(source):
+ """
+ https://newsapi.org/v1/articles?source=associated-press
+ """
+ url = base_url + "articles"
+ params = {"source": source,
+ "apiKey": NEWS_API_KEY,
+ "sortBy": "top"
+ }
+ print("requesting:", source)
+ resp = requests.get(url, params=params)
+ if resp.status_code != 200:
+ print("something went wrong with {}".format(source))
+ print(resp)
+ print(resp.text)
+ return []
+ data = resp.json()
+ # the url to the article itself is in data['articles'][i]['url']
+ new_titles = [str(art['title']) + str(art['description'])
+ for art in data['articles']]
+ titles.extend(new_titles)
+
+ #return titles
+
+def count_word(word, titles):
+ word = word.lower()
+ count = 0
+ for title in titles:
+ if word in title.lower():
+ count += 1
+ return count
+
+start = time.time()
+sources = get_sources()
+
+titles = []
+
+# I think this is how we might implement threading based on class examples
+# but I'm not sure since it's really difficult to test
+for source in sources:
+ for i in range(max_threads):
+ thread = threading.Thread(target=get_articles, args=[source])
+ thread.start()
+
+art_count = len(titles)
+word_count = count_word(WORD, titles)
+
+print(WORD, "found {} times in {} articles".format(word_count, art_count))
+print("Process took {:.0f} seconds".format(time.time() - start))
\ No newline at end of file
diff --git a/Student/stephen/lesson10/fib_pypy.py b/Student/stephen/lesson10/fib_pypy.py
new file mode 100644
index 0000000..89b8285
--- /dev/null
+++ b/Student/stephen/lesson10/fib_pypy.py
@@ -0,0 +1,73 @@
+"""
+I wanted to install pypy and test the difference
+with this simple script using the Fibonacci
+function we created earlier this class. However,
+I was met with errors which I appended at the bottom.
+Using regular cPython this script runs in 4.7 seconds.
+I tried creeating a virtual environment using python
+and the code from here:
+http://doc.pypy.org/en/latest/install.html#using-a-packaged-pypy
+"""
+from timeit import timeit as timer
+import random
+
+def fib(i=0):
+ j = 1
+ while True:
+ yield j
+ h = i
+ i = j
+ j = h + i
+
+random.seed(10)
+print('Running calculation of 1000 different Fibonacci numbers')
+print(timer('s = [fib(1000//random.random()) for i in range(10)]', globals=globals()))
+
+
+
+
+# ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson10/lesson10_assignment
+# $ mkvirtualenv -p /c/pypy3/pypy3 pypy_env
+# Running virtualenv with interpreter C:/pypy3/pypy3.exe
+# Using base prefix 'C:\\pypy3'
+# New pypy executable in C:\Users\ssouk\.virtualenvs\pypy_env\bin\pypy3.exe
+# Also creating executable in C:\Users\ssouk\.virtualenvs\pypy_env\bin\pypy.exe
+# Installing setuptools, pip, wheel...
+# Complete output from command C:\Users\ssouk\.virt...py_env\bin\pypy3.exe - setuptools pip wheel:
+# RPython traceback:
+# File "pypy_interpreter.c", line 42299, in BuiltinCode1_fastcall_1
+# File "pypy_module_posix.c", line 4913, in get_terminal_size
+# Traceback (most recent call last):
+# File "", line 27, in
+# File "c:\program files\python36\lib\site-packages\virtualenv_support\pip-10.0.1-py2.py3-none-any.whl\pip\_internal\__init__.py", line 232, in main
+# cmd_name, cmd_args = parseopts(args)
+# File "c:\program files\python36\lib\site-packages\virtualenv_support\pip-10.0.1-py2.py3-none-any.whl\pip\_internal\__init__.py", line 172, in parseopts
+# parser = create_main_parser()
+# File "c:\program files\python36\lib\site-packages\virtualenv_support\pip-10.0.1-py2.py3-none-any.whl\pip\_internal\__init__.py", line 144, in create_main_parser
+# 'formatter': UpdatingDefaultsHelpFormatter(),
+# File "c:\program files\python36\lib\site-packages\virtualenv_support\pip-10.0.1-py2.py3-none-any.whl\pip\_internal\baseparser.py", line 25, in __init__
+# kwargs['width'] = get_terminal_size()[0] - 2
+# File "c:\program files\python36\lib\site-packages\virtualenv_support\pip-10.0.1-py2.py3-none-any.whl\pip\_internal\compat.py", line 204, in get_terminal_size
+# return tuple(shutil.get_terminal_size())
+# File "C:\Users\ssouk\.virtualenvs\pypy_env\lib-python\3\shutil.py", line 1078, in get_terminal_size
+# size = os.get_terminal_size(sys.__stdout__.fileno())
+# SystemError: unexpected internal exception (please report a bug): ; internal traceback was dumped to stderr
+# ----------------------------------------
+# ...Installing setuptools, pip, wheel...done.
+# Traceback (most recent call last):
+# File "c:\program files\python36\lib\site-packages\virtualenv.py", line 2343, in
+# main()
+# File "c:\program files\python36\lib\site-packages\virtualenv.py", line 712, in main
+# symlink=options.symlink)
+# File "c:\program files\python36\lib\site-packages\virtualenv.py", line 947, in create_environment download=download,
+# File "c:\program files\python36\lib\site-packages\virtualenv.py", line 904, in install_wheel
+# call_subprocess(cmd, show_stdout=False, extra_env=env, stdin=SCRIPT) File "c:\program files\python36\lib\site-packages\virtualenv.py", line 796, in call_subprocess
+# % (cmd_desc, proc.returncode))
+# OSError: Command C:\Users\ssouk\.virt...py_env\bin\pypy3.exe - setuptools pip wheel failed with error code 1
+# ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson10/lesson10_assignment
+# $ python factorial_pypy.pyRunning factorial(10000)
+
+# ssouk@DESKTOP-9LI20UR MINGW64 ~/Documents/Python/Python Programming 220 AC/Lesson10/lesson10_assignment$ python fib_pypy.py
+# Running calculation of 1000 different Fibonacci numbers
+# 4.756364268184982