diff --git a/config.json b/config.json
new file mode 100644
index 0000000..b6a89fa
--- /dev/null
+++ b/config.json
@@ -0,0 +1,11 @@
+{
+ "server": {
+ "url": "127.0.0.1",
+ "port": 8000
+ },
+ "database":{
+ "name": "moocrank",
+ "url": "localhost",
+ "port": 27017
+ }
+}
\ No newline at end of file
diff --git a/data/coursera.json b/data/coursera.json
new file mode 100644
index 0000000..4d065ee
--- /dev/null
+++ b/data/coursera.json
@@ -0,0 +1 @@
+{"unis":[{"name":"Stanford University","short_name":"stanford","favicon":"https://coursera-university-assets.s3.amazonaws.com/dc/581cda352d067023dcdcc0d9efd36e/favicon-stanford.ico","home_link":"http://online.stanford.edu/","id":1,"display":true},{"name":"University of Michigan","short_name":"umich","favicon":"https://coursera-university-assets.s3.amazonaws.com/50/52265d555e7bf0b0b86f7a1a07a183/favicon-umich.ico","home_link":"","id":3,"display":true},{"name":"Princeton University","short_name":"princeton","favicon":"https://coursera-university-assets.s3.amazonaws.com/d4/29daf4b768e1aa467202d4d2dcf8d8/favicon-princeton.ico","home_link":null,"id":4,"display":true},{"name":"University of Pennsylvania","short_name":"penn","favicon":"https://coursera-university-assets.s3.amazonaws.com/f3/2ca37fd0d5d009a94e0ba7f284c860/favicon-penn.ico","home_link":null,"id":6,"display":true},{"name":"Duke University","short_name":"duke","favicon":"https://coursera-university-assets.s3.amazonaws.com/cc/500c9f41731d797a0e108a4edd8bc1/favicon-duke.ico","home_link":null,"id":7,"display":true},{"name":"Johns Hopkins University","short_name":"jhu","favicon":"https://coursera-university-assets.s3.amazonaws.com/80/d81353ccd0bab30962a5770d7aec97/favicon-jhu.ico","home_link":null,"id":8,"display":true},{"name":"Georgia Institute of Technology","short_name":"gatech","favicon":"https://coursera-university-assets.s3.amazonaws.com/88/4d9c7e8a6ad0e787553d8b9d77d450/favicon-gatech.ico","home_link":null,"id":9,"display":true},{"name":"University of California, San Francisco","short_name":"ucsf","favicon":"https://coursera-university-assets.s3.amazonaws.com/0c/2907cc15f65f9357cbaadd020c7949/favicon-ucsf.ico","home_link":null,"id":10,"display":true},{"name":"University of Toronto","short_name":"utoronto","favicon":"https://coursera-university-assets.s3.amazonaws.com/8e/773801b870a0cb946698134a77417d/favicon-utoronto.ico","home_link":null,"id":11,"display":true},{"name":"California Institute of Technology","short_name":"caltech","favicon":"https://coursera-university-assets.s3.amazonaws.com/1c/237c842c020ea0a3a6c9647d5cbd66/favicon-caltech.ico","home_link":null,"id":12,"display":true},{"name":"Rice University","short_name":"rice","favicon":"https://coursera-university-assets.s3.amazonaws.com/cc/17ce4ffdaddcc4aab941da137ddbbf/favicon-rice.ico","home_link":"","id":13,"display":true},{"name":"The University of Edinburgh","short_name":"edinburgh","favicon":"https://coursera-university-assets.s3.amazonaws.com/d3/bcdd33b2d979d2bea9467b17f9bbbb/favicon-edinburgh.ico","home_link":null,"id":14,"display":true},{"name":"University of Washington","short_name":"uw","favicon":"https://coursera-university-assets.s3.amazonaws.com/98/7480c1f9271144aa75fe024a1ad5a0/favicon-uw.ico","home_link":null,"id":15,"display":true},{"name":"\u00c9cole Polytechnique F\u00e9d\u00e9rale de Lausanne","short_name":"epfl","favicon":"https://coursera-university-assets.s3.amazonaws.com/ba/142188830b51c8c51b95cc25e5dbf3/epflfav.png","home_link":null,"id":16,"display":true},{"name":"University of Illinois at Urbana-Champaign","short_name":"illinois","favicon":"https://coursera-university-assets.s3.amazonaws.com/2b/57d79bc1eb5b081e6a1b3729782566/favicon.png","home_link":"","id":17,"display":true},{"name":"University of Virginia","short_name":"uva","favicon":"https://coursera-university-assets.s3.amazonaws.com/ba/8cf6b18a752fa9ba66be05d904571d/favicon-uva.ico","home_link":null,"id":18,"display":true},{"name":"Indian Institute of Technology Delhi","short_name":"iitd","favicon":"https://coursera-university-assets.s3.amazonaws.com/93/8531f10a9edadb75ba98db75fb5ad4/favicon-iitd.ico","home_link":"http://www.iitd.ac.in/","id":19,"display":false},{"name":"Berklee College of Music","short_name":"berklee","favicon":"https://coursera-university-assets.s3.amazonaws.com/10/bb37f439a00f92524143611e504b27/favicon.png","home_link":"","id":21,"display":true},{"name":"Brown University","short_name":"brown","favicon":"https://coursera-university-assets.s3.amazonaws.com/54/51fc6594a22ce0fcd31168f109900f/5_brown_icon_coursera.jpg","home_link":null,"id":22,"display":true},{"name":"Emory University","short_name":"emory","favicon":"https://coursera-university-assets.s3.amazonaws.com/a2/835a1009fc4245f378dd8add26dabc/Shield_280.jpg","home_link":null,"id":23,"display":true},{"name":"Hebrew University of Jerusalem","short_name":"huji","favicon":"https://coursera-university-assets.s3.amazonaws.com/48/7cac159746dca5674234142a147d0f/HebrewSmallIcon2.png","home_link":null,"id":24,"display":true},{"name":"Universiteit Leiden","short_name":"leiden","favicon":"https://coursera-university-assets.s3.amazonaws.com/ee/d18f6f5f5a5372c55cac5bc7f42b2a/ul_icon.gif","home_link":"","id":25,"display":true},{"name":"University of London International Programmes","short_name":"london","favicon":"https://coursera-university-assets.s3.amazonaws.com/b9/7737f6a77362b5ef13cb10fd1aeaa0/uol.ico","home_link":null,"id":26,"display":true},{"name":"Icahn School of Medicine at Mount Sinai","short_name":"mssm","favicon":"https://coursera-university-assets.s3.amazonaws.com/6e/050cc941c1081a711d979b25b7b108/Course_catalog_page_16x16.png","home_link":null,"id":27,"display":true},{"name":"The Ohio State University","short_name":"osu","favicon":"https://coursera-university-assets.s3.amazonaws.com/ae/1201e9f6249cafd6a532170780de3a/favicon-osu.png","home_link":null,"id":28,"display":true},{"name":"The University of British Columbia","short_name":"ubc","favicon":"https://coursera-university-assets.s3.amazonaws.com/d1/159770b1b64f0bb3736e0a1ad5144b/favicon.ico","home_link":null,"id":29,"display":true},{"name":"University of California, Irvine","short_name":"uci","favicon":"https://coursera-university-assets.s3.amazonaws.com/21/fe2ddd0d8a37bbb16033878eac3d75/16x16_uci.png","home_link":null,"id":30,"display":true},{"name":"University of Florida","short_name":"ufl","favicon":"https://coursera-university-assets.s3.amazonaws.com/a5/befae42322a4a691d65af982093ea8/favicon.png","home_link":null,"id":31,"display":true},{"name":"University of Maryland, College Park","short_name":"umd","favicon":"https://coursera-university-assets.s3.amazonaws.com/98/81bc9a607b97fadd8a2fdd6b66bfc2/favicon_16x16.ico","home_link":"","id":32,"display":true},{"name":"University of Melbourne","short_name":"unimelb","favicon":"https://coursera-university-assets.s3.amazonaws.com/c2/fc137263568a25c66e2cc5f98ca899/UOM_16x16pxLogo.png","home_link":null,"id":33,"display":true},{"name":"Wesleyan University","short_name":"wesleyan","favicon":"https://coursera-university-assets.s3.amazonaws.com/03/3d1139223689f57de761dd6783d8c3/6-wesleyan_small_icon.gif","home_link":null,"id":34,"display":true},{"name":"The Hong Kong University of Science and Technology","short_name":"hkust","favicon":"https://coursera-university-assets.s3.amazonaws.com/cb/c8497eeb219091d34206d663f73f27/ust_logo_16x16.png","home_link":null,"id":35,"display":true},{"name":"University of Pittsburgh","short_name":"pitt","favicon":"https://coursera-university-assets.s3.amazonaws.com/00/ee7a228aa46a231152d55b9bb9d0ae/logo_16x16.png","home_link":null,"id":36,"display":true},{"name":"Vanderbilt University","short_name":"vanderbilt","favicon":"https://coursera-university-assets.s3.amazonaws.com/76/5bf77c95f3afdcd6ff0c88fbf95693/vanderbilt_16x16_b.png","home_link":null,"id":37,"display":true},{"name":"Columbia University","short_name":"columbia","favicon":"https://coursera-university-assets.s3.amazonaws.com/72/c9b56e3ff66fa6e1ca52bdea9440ae/ColumbialittleLOGO4.png","home_link":null,"id":40,"display":true},{"name":"Mt. San Jacinto College","short_name":"msjc","favicon":"","home_link":"http://www.msjc.edu/Pages/default.aspx","id":44,"display":false},{"name":"The Chinese University of Hong Kong","short_name":"cuhk","favicon":"https://coursera-university-assets.s3.amazonaws.com/62/ee9401253f01a2b6446e8811865472/icon.png","home_link":null,"id":45,"display":true},{"name":"National University of Singapore","short_name":"nus","favicon":"","home_link":null,"id":47,"display":true},{"name":"University of Geneva","short_name":"unige","favicon":"https://coursera-university-assets.s3.amazonaws.com/2d/ced013338cdff809fbdde5a24f3354/UNIGE-SmallIcon-16x16.png","home_link":null,"id":49,"display":true},{"name":"University of Minnesota","short_name":"minnesota","favicon":"https://coursera-university-assets.s3.amazonaws.com/f2/c0c3766390def44d6704f82d4d7955/favicon.ico","home_link":null,"id":50,"display":true},{"name":"Pennsylvania State University","short_name":"psu","favicon":"https://coursera-university-assets.s3.amazonaws.com/be/4a6da97cb18e3f0543e11305aeec3b/psu_favicon.png","home_link":null,"id":51,"display":true},{"name":"University of California, San Diego ","short_name":"ucsd","favicon":"","home_link":null,"id":53,"display":true},{"name":"Northwestern University","short_name":"northwestern","favicon":"","home_link":null,"id":54,"display":true},{"name":"University of California, Santa Cruz","short_name":"ucsc","favicon":"","home_link":null,"id":56,"display":true},{"name":"Technical University of Denmark (DTU)","short_name":"dtu","favicon":"https://coursera-university-assets.s3.amazonaws.com/8b/1ab7b5448abdcd28732eb55226c501/DTUlogoSmall_nobg.png","home_link":null,"id":57,"display":true},{"name":"Universidad Nacional Aut\u00f3noma de M\u00e9xico","short_name":"unam","favicon":"","home_link":null,"id":58,"display":true},{"name":"California Institute of the Arts","short_name":"calarts","favicon":"","home_link":null,"id":59,"display":true},{"name":"University of Rochester","short_name":"rochester","favicon":"","home_link":null,"id":60,"display":true},{"name":"IE Business School","short_name":"ie","favicon":"https://coursera-university-assets.s3.amazonaws.com/18/9c556b9d2a5990ef6cb2839a0c5dc3/1university_logo.png","home_link":null,"id":61,"display":true},{"name":"Tecnol\u00f3gico de Monterrey","short_name":"tecdemonterrey","favicon":"","home_link":null,"id":62,"display":true},{"name":"University of Copenhagen","short_name":"ucph","favicon":"https://coursera-university-assets.s3.amazonaws.com/55/45a9eafa2bfdb29d961f8472a0b7fa/favicon_fa.ico","home_link":null,"id":63,"display":true},{"name":"Ludwig-Maximilians-Universit\u00e4t M\u00fcnchen (LMU)","short_name":"lmu","favicon":"https://coursera-university-assets.s3.amazonaws.com/0e/9145506f8bafba7c4c29fdde573a60/Unbenannt-4.png","home_link":null,"id":64,"display":true},{"name":"University of Wisconsin\u2013Madison","short_name":"wisconsin","favicon":"https://coursera-university-assets.s3.amazonaws.com/e4/4fd5046adaccc8414bb742946bcdba/uwcrest_web_sm_shado.png","home_link":null,"id":65,"display":true},{"name":"\u00c9cole Polytechnique","short_name":"ep","favicon":"https://coursera-university-assets.s3.amazonaws.com/9e/afbf6718f5c81f1e31d11aa1b47dff/logo_POLYTECHNIQUE_16X16px.png","home_link":null,"id":66,"display":true},{"name":"Rutgers University","short_name":"rutgers","favicon":"","home_link":null,"id":67,"display":true},{"name":"Case Western Reserve University","short_name":"casewestern","favicon":"","home_link":null,"id":68,"display":true},{"name":"University of Colorado Boulder","short_name":"boulder","favicon":"","home_link":null,"id":71,"display":true},{"name":"Sapienza University of Rome","short_name":"sapienza","favicon":"https://coursera-university-assets.s3.amazonaws.com/4f/07577f978824782011a597f14f2bdf/favicon-16x16-png.png","home_link":null,"id":74,"display":true},{"name":"National Taiwan University","short_name":"taiwan","favicon":"","home_link":null,"id":75,"display":true},{"name":"The University of Tokyo","short_name":"todai","favicon":"","home_link":null,"id":76,"display":true},{"name":"The University of North Carolina at Chapel Hill","short_name":"unc","favicon":"","home_link":null,"id":77,"display":true},{"name":"Technische Universit\u00e4t M\u00fcnchen (TUM)","short_name":"tum","favicon":"","home_link":null,"id":78,"display":true},{"name":"Curtis Institute of Music","short_name":"curtis","favicon":"","home_link":null,"id":79,"display":true},{"name":"Universitat Aut\u00f2noma de Barcelona","short_name":"uab","favicon":"","home_link":null,"id":80,"display":true},{"name":"American Museum of Natural History","short_name":"amnh","favicon":"https://coursera-university-assets.s3.amazonaws.com/78/6a808ab06c1ffef534768de3a0e8a2/icon_logo.png","home_link":"","id":100,"display":true},{"name":"New Teacher Center","short_name":"ntc","favicon":"https://coursera-university-assets.s3.amazonaws.com/33/168213375fa6e522c6e373a457566b/favicon.png","home_link":"","id":103,"display":true},{"name":"Relay Graduate School of Education","short_name":"relay","favicon":"https://coursera-university-assets.s3.amazonaws.com/c1/8aa8e4ca6c35946b8f91513912604a/Relay_favicon_16x16.png","home_link":"","id":104,"display":true},{"name":"Match Teacher Residency","short_name":"mtr","favicon":"","home_link":"","id":105,"display":true},{"name":"Commonwealth Education Trust","short_name":"cet1886","favicon":"https://coursera-university-assets.s3.amazonaws.com/9d/6339cee6ef32f274cc50dd912e84d4/favicon.png","home_link":"","id":106,"display":true},{"name":"The Museum of Modern Art","short_name":"moma","favicon":"https://coursera-university-assets.s3.amazonaws.com/2d/3ce9358bedaecb4792e2f14a0651cc/coursera_180x180.png","home_link":"","id":107,"display":true},{"name":"Exploratorium","short_name":"exploratorium","favicon":"","home_link":"","id":108,"display":true},{"name":"Yale University","short_name":"yale","favicon":"","home_link":"","id":109,"display":true},{"name":"Tel Aviv University","short_name":"telaviv","favicon":"https://coursera-university-assets.s3.amazonaws.com/be/47ef4e542b6cf91426d91b3325a4eb/image001.png","home_link":"","id":110,"display":true},{"name":"Technion - Israel Institute of Technology","short_name":"technion","favicon":"","home_link":"","id":129,"display":true}],"topics":{"2":{"insts":[1244],"language":"en","name":"Machine Learning","short_name":"ml","order_idx":0,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/ml/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/ml/large-icon.png","cats":[16,17],"unis":[1],"id":2},"3":{"insts":[1257],"language":"en","name":"Probabilistic Graphical Models","short_name":"pgm","order_idx":1,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/pgm/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/pgm/large-icon.png","cats":[17],"unis":[1],"id":3},"6":{"insts":[1250],"language":"en","name":"Human-Computer Interaction","short_name":"hci","order_idx":2,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/hci/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/hci/large-icon.png","cats":[4,12],"unis":[1],"id":6},"7":{"insts":[775,68850],"language":"en","name":"Natural Language Processing","short_name":"nlp","order_idx":3,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/nlp/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/nlp/large-icon.png","cats":[17],"unis":[1],"id":7},"8":{"insts":[768],"language":"en","name":"Algorithms: Design and Analysis, Part 1","short_name":"algo","order_idx":4,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/algo/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/algo/large-icon.png","cats":[1],"unis":[1],"id":8},"9":{"insts":[774],"language":"en","name":"Cryptography I","short_name":"crypto","order_idx":5,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/crypto/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/crypto/large-icon.png","cats":[1,11],"unis":[1],"id":9},"11":{"insts":[785],"language":"en","name":"Model Thinking","short_name":"modelthinking","order_idx":6,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/modelthinking/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/modelthinking/large-icon.png","cats":[2,6],"unis":[3],"id":11},"12":{"insts":[1196954],"language":"en","name":"Introduction to Databases","short_name":"db","order_idx":7,"self_service_course_id":32,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/cb/61b70b13451469aa582fc91d020f64/dbLogo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c9/643d403b593b865b40c64b0f6cc33c/dbLogo.jpg","cats":[11,12],"unis":[1],"id":12},"13":{"insts":[1267],"language":"en","name":"Computer Science 101","short_name":"cs101","order_idx":8,"self_service_course_id":380,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/cs101/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/cs101/large-icon.png","cats":[12],"unis":[1],"id":13},"14":{"insts":[1271],"language":"en","name":"Automata","short_name":"automata","order_idx":9,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/automata/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/automata/large-icon.png","cats":[1],"unis":[1],"id":14},"15":{"insts":[1460],"language":"en","name":"Introduction to Logic","short_name":"intrologic","order_idx":10,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/intrologic/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/intrologic/large-icon.png","cats":[1,5],"unis":[1],"id":15},"16":{"insts":[221514],"language":"en","name":"Compilers","short_name":"compilers","order_idx":11,"self_service_course_id":378,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/compilers/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/compilers/large-icon.png","cats":[11,12],"unis":[1],"id":16},"19":{"insts":[774,95,1039793],"language":"en","name":"Computer Security","short_name":"security","order_idx":12,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/40/89e1c7e5b1209fd587aae6fe8615af/more-height_2.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/16/14c599959bd3d6e7b0a710e7d4eb5f/more-height_2.png","cats":[11],"unis":[1],"id":19},"20":{"insts":[174814,1252,1251],"language":"en","name":"Game Theory","short_name":"gametheory","order_idx":13,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/gametheory/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/gametheory/large-icon.png","cats":[1,2,17],"unis":[1,29],"id":20},"22":{"insts":[224886],"language":"en","name":"Modern & Contemporary American Poetry","short_name":"modernpoetry","order_idx":14,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/modernpoetry/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/modernpoetry/large-icon.png","cats":[6,22],"unis":[6],"id":22},"23":{"insts":[239857],"language":"en","name":"Introduction to Sociology","short_name":"soc101","order_idx":15,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/soc101/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/soc101/large-icon.png","cats":[20],"unis":[4],"id":23},"24":{"insts":[419989],"language":"en","name":"Computer Architecture","short_name":"comparch","order_idx":16,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/comparch/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/comparch/large-icon.png","cats":[11,15],"unis":[4],"id":24},"25":{"insts":[419984],"language":"en","name":"Statistics One","short_name":"stats1","order_idx":17,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/04/95377c7b544250674cd4fb40792a6f/course-logo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/7c/7f9a5ca0231d151c230f3feb8f3c38/course-logo.png","cats":[16],"unis":[4],"id":25},"26":{"insts":[246867,250165],"language":"en","name":"Algorithms, Part I","short_name":"algs4partI","order_idx":18,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/algs4partI/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/algs4partI/large-icon.png","cats":[1,12],"unis":[4],"id":26},"27":{"insts":[246867,250165],"language":"en","name":"Algorithms, Part II","short_name":"algs4partII","order_idx":19,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/algs4partII/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/algs4partII/large-icon.png","cats":[1,12],"unis":[4],"id":27},"28":{"insts":[235007],"language":"en","name":"Listening to World Music","short_name":"worldmusic","order_idx":20,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/worldmusic/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/worldmusic/large-icon.png","cats":[6,18],"unis":[6],"id":28},"29":{"insts":[422471],"language":"en","name":"Greek and Roman Mythology","short_name":"mythology","order_idx":21,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/mythology/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/mythology/large-icon.png","cats":[6],"unis":[6],"id":29},"30":{"insts":[227062],"language":"en","name":"Calculus: Single Variable","short_name":"calcsing","order_idx":22,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/90/f1e8b1866fc2c8ab40a94b89bddef0/new-logo-CSV.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/dc/38555ec0e850c23a5efa3184982242/new-logo-CSV.jpg","cats":[5],"unis":[6],"id":30},"31":{"insts":[555881],"language":"en","name":"Networked Life","short_name":"networks","order_idx":23,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/networks/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/networks/large-icon.png","cats":[4,17],"unis":[6],"id":31},"32":{"insts":[226710],"language":"en","name":"Gamification","short_name":"gamification","order_idx":24,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/gamification/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/gamification/large-icon.png","cats":[4,13],"unis":[6],"id":32},"33":{"insts":[1806984],"language":"en","name":"Health Policy and the Affordable Care Act","short_name":"healthpolicy","order_idx":25,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/healthpolicy/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/healthpolicy/large-icon.png","cats":[2,8],"unis":[6],"id":33},"34":{"insts":[654632],"language":"en","name":"Vaccines","short_name":"vaccines","order_idx":26,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/vaccines/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/vaccines/large-icon.png","cats":[3,8],"unis":[6],"id":34},"35":{"insts":[471278],"language":"en","name":"Fundamentals of Pharmacology","short_name":"pharm101","order_idx":27,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/pharm101/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/pharm101/large-icon.png","cats":[3],"unis":[6],"id":35},"36":{"insts":[2666347,237513],"language":"en","name":"Cardiac Arrest, Hypothermia, and Resuscitation Science","short_name":"cardiacarrest","order_idx":28,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/cardiacarrest/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/cardiacarrest/large-icon.png","cats":[3],"unis":[6],"id":36},"37":{"insts":[2666366],"language":"en","name":"Basic Behavioral Neurology","short_name":"neurobehavior","order_idx":29,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/neurobehavior/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/neurobehavior/large-icon.png","cats":[3,10],"unis":[6],"id":37},"38":{"insts":[123682],"language":"en","name":"Social Network Analysis","short_name":"sna","order_idx":30,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/sna/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/sna/large-icon.png","cats":[4,17],"unis":[3],"id":38},"39":{"insts":[715252],"language":"en","name":"Securing Digital Democracy","short_name":"digitaldemocracy","order_idx":31,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/digitaldemocracy/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/digitaldemocracy/large-icon.png","cats":[4,11],"unis":[3],"id":39},"40":{"insts":[209008],"language":"en","name":"Introduction to Finance","short_name":"introfinance","order_idx":32,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/introfinance/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/introfinance/large-icon.png","cats":[2,13],"unis":[3],"id":40},"41":{"insts":[806928],"language":"en","name":"Fantasy and Science Fiction: The Human Mind, Our Modern World","short_name":"fantasysf","order_idx":33,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/fantasysf/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/fantasysf/large-icon.png","cats":[6],"unis":[3],"id":41},"42":{"insts":[122340],"language":"en","name":"Internet History, Technology, and Security","short_name":"insidetheinternet","order_idx":34,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/insidetheinternet/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/insidetheinternet/large-icon.png","cats":[4,11],"unis":[3],"id":42},"43":{"insts":[2666324,2666329],"language":"en","name":"Computer Vision: From 3D Reconstruction to Visual Recognition","short_name":"computervision","order_idx":35,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/computervision/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/computervision/large-icon.png","cats":[17],"unis":[1,3],"id":43},"44":{"insts":[471335,1320449],"language":"en","name":"Experimental Genome Science","short_name":"genomescience","order_idx":36,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/genomescience/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/genomescience/large-icon.png","cats":[10],"unis":[6],"id":44},"45":{"insts":[419843],"language":"en","name":"A History of the World since 1300","short_name":"wh1300","order_idx":37,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/wh1300/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/wh1300/large-icon.png","cats":[6],"unis":[4],"id":45},"48":{"insts":[423879],"language":"en","name":"Networks: Friends, Money, and Bytes","short_name":"friendsmoneybytes","order_idx":38,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/friendsmoneybytes/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/friendsmoneybytes/large-icon.png","cats":[2,4,11],"unis":[4],"id":48},"50":{"insts":[435103],"language":"en","name":"Neuroethics","short_name":"neuroethics","order_idx":39,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/neuroethics/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/neuroethics/large-icon.png","cats":[8],"unis":[6],"id":50},"51":{"insts":[1806984],"language":"en","name":"Rationing and Allocating Scarce Medical Resources","short_name":"rationing","order_idx":40,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/rationing/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/rationing/large-icon.png","cats":[8],"unis":[6],"id":51},"53":{"insts":[932645],"language":"en","name":"Bioelectricity: A Quantitative Approach","short_name":"bioelectricity","order_idx":41,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/bioelectricity/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/bioelectricity/large-icon.png","cats":[10,23],"unis":[7],"id":53},"54":{"insts":[963741,972090],"language":"en","name":"Healthcare Innovation and Entrepreneurship","short_name":"healthcareinnovation","order_idx":42,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/healthcareinnovation/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/healthcareinnovation/large-icon.png","cats":[8,13],"unis":[7],"id":54},"55":{"insts":[868977,920567],"language":"en","name":"Introductory Human Physiology","short_name":"humanphysio","order_idx":43,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/humanphysio/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/humanphysio/large-icon.png","cats":[3,10],"unis":[7],"id":55},"56":{"insts":[884310],"language":"en","name":"Introduction to Genetics and Evolution","short_name":"geneticsevolution","order_idx":44,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/geneticsevolution/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/geneticsevolution/large-icon.png","cats":[10],"unis":[7],"id":56},"57":{"insts":[638605],"language":"en","name":"Introduction to Astronomy","short_name":"introastro","order_idx":45,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/introastro/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/introastro/large-icon.png","cats":[23],"unis":[7],"id":57},"58":{"insts":[932346,935146],"language":"en","name":"Think Again: How to Reason and Argue","short_name":"thinkagain","order_idx":46,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/thinkagain/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/thinkagain/large-icon.png","cats":[6],"unis":[7],"id":58},"59":{"insts":[901314],"language":"en","name":"Medical Neuroscience","short_name":"medicalneuro","order_idx":47,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/medicalneuro/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/medicalneuro/large-icon.png","cats":[3,10],"unis":[7],"id":59},"60":{"insts":[681795,682843],"language":"en","name":"Learn to Program: The Fundamentals","short_name":"programming1","order_idx":48,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/programming1/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/programming1/large-icon.png","cats":[12],"unis":[11],"id":60},"61":{"insts":[694443],"language":"en","name":"Data Analysis","short_name":"dataanalysis","order_idx":49,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/48/86bad71cff7e0534af3a389fff7fe5/data.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f1/07934f1dada74bcd7d61c79041843e/data.jpg","cats":[8,16],"unis":[8],"id":61},"62":{"insts":[681157],"language":"en","name":"Principles of Obesity Economics","short_name":"obesityecon","order_idx":50,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/16/bfb25309f862d1ed63485c52081ed0/obesity_new.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/0d/3ab208ef03bb73a6f86734aaa64530/obesity_new.png","cats":[2,8,19],"unis":[8],"id":62},"63":{"insts":[685384],"language":"en","name":"Computing for Data Analysis","short_name":"compdata","order_idx":51,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7c/4217ec129f44745919bec2e990e012/computing.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c6/0b6be777b4a4f1d26c879fa4a2c4e2/computing.jpg","cats":[8,16],"unis":[8],"id":63},"65":{"insts":[883324],"language":"en","name":"Clinical Problem Solving","short_name":"clinprobsolv","order_idx":52,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/clinprobsolv/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/clinprobsolv/large-icon.png","cats":[3],"unis":[10],"id":65},"66":{"insts":[681795,682843],"language":"en","name":"Learn to Program: Crafting Quality Code","short_name":"programming2","order_idx":53,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/programming2/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/programming2/large-icon.png","cats":[12],"unis":[11],"id":66},"67":{"insts":[994329],"language":"en","name":"Nutrition for Health Promotion and Disease Prevention","short_name":"nutrition","order_idx":54,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/nutrition/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/nutrition/large-icon.png","cats":[2,3,8,19],"unis":[10],"id":67},"68":{"insts":[688901],"language":"en","name":"Mathematical Biostatistics Boot Camp","short_name":"biostats","order_idx":55,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f9/07bcfc8529d60df8dcadbd77cbd1a5/bootcamp.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6a/c2d2a4237871d4d7651d9bd88bd5eb/bootcamp.jpg","cats":[5,8,10,16],"unis":[8],"id":68},"69":{"insts":[868795],"language":"en","name":"Contraception: Choices, Culture and Consequences","short_name":"contraception","order_idx":56,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/contraception/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/contraception/large-icon.png","cats":[3,8],"unis":[10],"id":69},"70":{"insts":[874189],"language":"en","name":"Aboriginal Worldviews and Education","short_name":"aboriginaled","order_idx":57,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/aboriginaled/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/aboriginaled/large-icon.png","cats":[6,14],"unis":[11],"id":70},"71":{"insts":[693038],"language":"en","name":"Health for All Through Primary Health Care","short_name":"healthforall","order_idx":58,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/e3/4d0373cf2c2dc5c7b70603dce172fb/HealthForAll_3.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ca/dca34788554ed6ddff6113b9c0388a/HealthForAll_3.png","cats":[3,8],"unis":[8],"id":71},"72":{"insts":[687518,2286634],"language":"en","name":"An Introduction to the U.S. Food System: Perspectives from Public Health","short_name":"foodsys","order_idx":59,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/67/9759547d462a7edf0a42eb82bc553b/food_new.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/1b/d070451e6274d1f82a4a6830443459/food_new.png","cats":[8,19],"unis":[8],"id":72},"74":{"insts":[660062],"language":"en","name":"Community Change in Public Health","short_name":"communitychange","order_idx":60,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/78/a1678398f6c403c05f2481f192a5fc/community.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ca/b94bda74a7a5686674861cbb9eeaba/community.jpg","cats":[8],"unis":[8],"id":74},"77":{"insts":[831097],"language":"en","name":"Neural Networks for Machine Learning","short_name":"neuralnets","order_idx":61,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/neuralnets/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/neuralnets/large-icon.png","cats":[16,17],"unis":[11],"id":77},"78":{"insts":[598777,603309],"language":"en","name":"Vaccine Trials: Methods and Best Practices","short_name":"vacctrials","order_idx":62,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/59/a02689da9d26c589fff4f4f786c6e2/vaccine_2-02.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/96/d2c9b76077f473bdf7a2bf4eb141b3/vaccine_2-02.png","cats":[3,8],"unis":[8],"id":78},"80":{"insts":[882099],"language":"en","name":"The Social Context of Mental Health and Illness","short_name":"mentalhealth","order_idx":63,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/mentalhealth/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/mentalhealth/large-icon.png","cats":[8],"unis":[11],"id":80},"81":{"insts":[685941],"language":"en","name":"Galaxies and Cosmology","short_name":"cosmo","order_idx":64,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/cosmo/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/cosmo/large-icon.png","cats":[23],"unis":[12],"id":81},"82":{"insts":[459667],"language":"en","name":"Principles of Economics for Scientists","short_name":"econ1scientists","order_idx":65,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/econ1scientists/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/econ1scientists/large-icon.png","cats":[2],"unis":[12],"id":82},"83":{"insts":[640696],"language":"en","name":"Drugs and the Brain","short_name":"drugsandbrain","order_idx":66,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/drugsandbrain/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/drugsandbrain/large-icon.png","cats":[3,10],"unis":[12],"id":83},"84":{"insts":[2225883,247285],"language":"en","name":"Control of Mobile Robots","short_name":"conrob","order_idx":67,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/conrob/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/conrob/large-icon.png","cats":[15,17],"unis":[9],"id":84},"85":{"insts":[862822,2225883],"language":"en","name":"Energy 101","short_name":"energy101","order_idx":68,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/energy101/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/energy101/large-icon.png","cats":[25],"unis":[9],"id":85},"86":{"insts":[861614,2225883],"language":"en","name":"Computational Investing, Part I","short_name":"compinvesting1","order_idx":69,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/compinvesting1/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/compinvesting1/large-icon.png","cats":[2,17],"unis":[9],"id":86},"87":{"insts":[868530,2225883],"language":"en","name":"Computational Photography","short_name":"compphoto","order_idx":70,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/compphoto/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/compphoto/large-icon.png","cats":[4,17],"unis":[9],"id":87},"88":{"insts":[527518,726142,530929,695900],"language":"en","name":"An Introduction to Interactive Programming in Python","short_name":"interactivepython","order_idx":71,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/interactivepython/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/interactivepython/large-icon.png","cats":[12],"unis":[13],"id":88},"89":{"insts":[861494,2225883],"language":"en","name":"Fundamentals of Online Education: Planning and Application","short_name":"foe","order_idx":72,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/foe/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/foe/large-icon.png","cats":[4,14],"unis":[9],"id":89},"90":{"insts":[557195],"language":"en","name":"Fundamentals of Electrical Engineering","short_name":"eefun","order_idx":73,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/eefun/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/eefun/large-icon.png","cats":[15],"unis":[13],"id":90},"91":{"insts":[2280464],"language":"en","name":"Analytical Chemistry / Instrumental Analysis","short_name":"analyticalchem","order_idx":74,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/analyticalchem/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/analyticalchem/large-icon.png","cats":[24],"unis":[13],"id":91},"92":{"insts":[2666905],"language":"en","name":"Chemistry: Concept Development and Application","short_name":"genchem1","order_idx":75,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/genchem1/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/genchem1/large-icon.png","cats":[24],"unis":[13],"id":92},"93":{"insts":[2280464,2666907],"language":"en","name":"Nanotechnology: The Basics","short_name":"nanotech","order_idx":76,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/nanotech/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/nanotech/large-icon.png","cats":[15,23,24],"unis":[13],"id":93},"94":{"insts":[585759,895139],"language":"en","name":"Artificial Intelligence Planning","short_name":"aiplan","order_idx":77,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/aiplan/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/aiplan/large-icon.png","cats":[17],"unis":[14],"id":94},"95":{"insts":[1506477],"language":"en","name":"Building an Information Risk Management Toolkit","short_name":"inforisk","order_idx":78,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/56/3d5827c565edde379dabc12ba8f36c/small-icon.hover.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/bc/1b1da1510430626d00a99244019e0a/small-icon.hover.png","cats":[4,11],"unis":[15],"id":95},"96":{"insts":[2666846],"language":"en","name":"Computational Methods for Data Analysis","short_name":"compmethods","order_idx":79,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/36/2ef3cdd658ded09646057a0e57e74a/large-icon.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/67/87122bcf2af464883dfa168482ea58/large-icon.png","cats":[16],"unis":[15],"id":96},"97":{"insts":[1522272,1282559],"language":"en","name":"Computational Neuroscience","short_name":"compneuro","order_idx":80,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/compneuro/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/compneuro/large-icon.png","cats":[10,17],"unis":[15],"id":97},"98":{"language":"en","name":"Astrobiology and the Search for Extraterrestrial Life","short_name":"astrobio","order_idx":81,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/astrobio/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/astrobio/large-icon.png","insts":[796896],"unis":[14],"id":98},"100":{"insts":[2865239],"language":"en","name":"Designing and Executing Information Security Strategies","short_name":"infosec","order_idx":82,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/84/ce92a9ce848f5862c4d6d02c27c669/graphic.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/25/ee713c3571eb24f91c8e4ccdb40f11/graphic.png","cats":[4,11],"unis":[15],"id":100},"102":{"insts":[2666846],"language":"en","name":"Scientific Computing","short_name":"scientificcomp","order_idx":83,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/scientificcomp/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/scientificcomp/large-icon.png","cats":[16],"unis":[15],"id":102},"103":{"insts":[1506477],"language":"en","name":"Information Security and Risk Management in Context","short_name":"inforiskman","order_idx":84,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/inforiskman/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/inforiskman/large-icon.png","cats":[4,11],"unis":[15],"id":103},"105":{"insts":[517478,525208,1020740],"language":"en","name":"Computer Networks","short_name":"comnetworks","order_idx":85,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/comnetworks/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/comnetworks/large-icon.png","cats":[4,11,15],"unis":[15],"id":105},"106":{"insts":[999946],"language":"en","name":"Introduction to Data Science","short_name":"datasci","order_idx":86,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/datasci/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/datasci/large-icon.png","cats":[4,11,12,16],"unis":[15],"id":106},"108":{"insts":[1604596,1935119,1935226,1935218,1935223,1935212,1935209],"language":"en","name":"Introduction to Philosophy","short_name":"introphil","order_idx":87,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/introphil/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/introphil/large-icon.png","cats":[6],"unis":[14],"id":108},"110":{"insts":[1604583],"language":"en","name":"Equine Nutrition","short_name":"equinenutrition","order_idx":88,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/equinenutrition/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/equinenutrition/large-icon.png","cats":[3],"unis":[14],"id":110},"114":{"insts":[920057,1016886],"language":"en","name":"Critical Thinking in Global Challenges","short_name":"criticalthinking","order_idx":89,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/criticalthinking/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/criticalthinking/large-icon.png","cats":[8,10,25],"unis":[14],"id":114},"115":{"insts":[950832,306499,1862154,1292208,1301316],"language":"en","name":"E-learning and Digital Cultures","short_name":"edc","order_idx":90,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/edc/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/edc/large-icon.png","cats":[14],"unis":[14],"id":115},"116":{"insts":[672627],"language":"en","name":"Functional Programming Principles in Scala","short_name":"progfun","order_idx":91,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/progfun/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/progfun/large-icon.png","cats":[12],"unis":[16],"id":116},"117":{"insts":[873260],"language":"en","name":"Programming Languages","short_name":"proglang","order_idx":92,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/proglang/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/proglang/large-icon.png","cats":[12],"unis":[15],"id":117},"119":{"insts":[1320364],"language":"en","name":"High Performance Scientific Computing","short_name":"scicomp","order_idx":93,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/00/621b9b2597807229ed0fa605f96cdc/HighPerformanceComputingIma.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/7b/3247a51d254d7f0c68062147957e53/HighPerformanceComputingIma.jpg","cats":[4,16],"unis":[15],"id":119},"121":{"insts":[676340,2141686],"language":"en","name":"Digital Signal Processing","short_name":"dsp","order_idx":94,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/dsp/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/dsp/large-icon.png","cats":[15],"unis":[16],"id":121},"122":{"insts":[2602091,1562358],"language":"en","name":"The Hardware/Software Interface","short_name":"hwswinterface","order_idx":95,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/hardware/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/hardware/large-icon.png","cats":[11],"unis":[15],"id":122},"123":{"insts":[680709],"language":"en","name":"A Beginner's Guide to Irrational Behavior","short_name":"behavioralecon","order_idx":96,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/behavioralecon/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/behavioralecon/large-icon.png","cats":[2,6],"unis":[7],"id":123},"124":{"insts":[587683],"language":"en","name":"Introduction to Mathematical Thinking","short_name":"maththink","order_idx":97,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/maththink/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/maththink/large-icon.png","cats":[5],"unis":[1],"id":124},"125":{"insts":[1349478],"language":"en","name":"An Introduction to Operations Management","short_name":"operations","order_idx":98,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/operations/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/operations/large-icon.png","cats":[13],"unis":[6],"id":125},"126":{"insts":[341966],"language":"en","name":"Design: Creation of Artifacts in Society","short_name":"design","order_idx":99,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/design/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/design/large-icon.png","cats":[4,13,15,22],"unis":[6],"id":126},"127":{"insts":[774],"language":"en","name":"Cryptography II","short_name":"crypto2","order_idx":100,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/crypto2/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/crypto2/large-icon.png","cats":[1,11],"unis":[1],"id":127},"128":{"insts":[768],"language":"en","name":"Algorithms: Design and Analysis, Part 2","short_name":"algo2","order_idx":101,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/algo2/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/algo2/large-icon.png","cats":[1],"unis":[1],"id":128},"129":{"insts":[917653],"language":"en","name":"Heterogeneous Parallel Programming","short_name":"hetero","order_idx":102,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/hetero/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/hetero/large-icon.png","cats":[11,12],"unis":[17],"id":129},"130":{"insts":[887472],"language":"en","name":"VLSI CAD: Logic to Layout","short_name":"vlsicad","order_idx":103,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/vlsicad/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/vlsicad/large-icon.png","cats":[11,15],"unis":[17],"id":130},"131":{"insts":[902954],"language":"en","name":"Creative, Serious and Playful Science of Android Apps","short_name":"androidapps101","order_idx":104,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/androidapps101/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/androidapps101/large-icon.png","cats":[12],"unis":[17],"id":131},"132":{"insts":[2135893],"language":"en","name":"The Modern World: Global History since 1760","short_name":"modernworld","order_idx":105,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/42/08338b124dd8165f27ea86fc99f569/Flag-Globe.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/d2/0daecfe0161d8305452f9650ea2eaf/Flag-Globe.png","cats":[6],"unis":[18],"id":132},"135":{"insts":[988020],"language":"en","name":"Grow to Greatness: Smart Growth for Private Businesses, Part I","short_name":"growtogreatness","order_idx":106,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/growtogreatness/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/growtogreatness/large-icon.png","cats":[13],"unis":[18],"id":135},"136":{"insts":[901931],"language":"en","name":"Introduction to Sustainability","short_name":"sustain","order_idx":107,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/sustain/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/sustain/large-icon.png","cats":[25],"unis":[17],"id":136},"137":{"insts":[901980],"language":"en","name":"Planet Earth","short_name":"earth","order_idx":108,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/earth/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/earth/large-icon.png","cats":[25],"unis":[17],"id":137},"138":{"insts":[884324],"language":"en","name":"Microeconomics Principles","short_name":"microecon","order_idx":109,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/microecon/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/microecon/large-icon.png","cats":[2],"unis":[17],"id":138},"139":{"insts":[903698,907436,938149],"language":"en","name":"Introductory Organic Chemistry - Part 1","short_name":"orgchem1a","order_idx":110,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/orgchem1a/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/orgchem1a/large-icon.png","cats":[24],"unis":[17],"id":139},"140":{"insts":[903698,907436,938149],"language":"en","name":"Introductory Organic Chemistry - Part 2","short_name":"orgchem1b","order_idx":111,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/orgchem1b/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/orgchem1b/large-icon.png","cats":[24],"unis":[17],"id":140},"141":{"insts":[903698,907436],"language":"en","name":"Intermediate Organic Chemistry - Part 1","short_name":"orgchem2a","order_idx":112,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/orgchem2a/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/orgchem2a/large-icon.png","cats":[24],"unis":[17],"id":141},"143":{"insts":[903698,907436,938149],"language":"en","name":"Intermediate Organic Chemistry - Part 2","short_name":"orgchem2b","order_idx":113,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/orgchem2b/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/orgchem2b/large-icon.png","cats":[24],"unis":[17],"id":143},"144":{"insts":[1074054,1116355,1345762],"language":"fr","name":"Introduction \u00e0 la programmation orient\u00e9e objet (en Java)","short_name":"java-fr","order_idx":114,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/b3/eab749947a1a90468fa53d0e066aea/IMG_1580_2_2_4.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/2e/32c22e658344980fb3bd62e64f4171/IMG_1580_2_2_4.jpg","cats":[12],"unis":[16],"id":144},"145":{"insts":[107347],"language":"en","name":"Web Intelligence and Big Data","short_name":"bigdata","order_idx":115,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/bigdata/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/bigdata/large-icon.png","cats":[17],"unis":[19],"id":145},"147":{"insts":[1139667],"language":"en","name":"Organizational Analysis","short_name":"organalysis","order_idx":116,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/organalysis/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/organalysis/large-icon.png","cats":[13],"unis":[1],"id":147},"148":{"insts":[1118525],"language":"en","name":"Introduction to Computational Finance and Financial Econometrics","short_name":"compfinance","order_idx":117,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/compfinance/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/compfinance/large-icon.png","cats":[2],"unis":[15],"id":148},"153":{"insts":[729871],"language":"en","name":"Image and video processing: From Mars to Hollywood with a stop at the hospital","short_name":"images","order_idx":118,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/images/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/images/large-icon.png","cats":[5,15,17],"unis":[7],"id":153},"154":{"insts":[988020],"language":"en","name":"Grow to Greatness: Smart Growth for Private Businesses, Part II","short_name":"GTG","order_idx":119,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7c/9268909c2ef573dedeec650adbd3b5/Faded-logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/75/fd5853cdf1752a1e01d69da5e8cf73/Faded-logo.jpg","cats":[13],"unis":[18],"id":154},"157":{"insts":[1367410],"language":"en","name":"Writing in the Sciences","short_name":"sciwrite","order_idx":120,"self_service_course_id":null,"small_icon_hover":"https://s3.amazonaws.com/coursera/topics/sciwrite/small-icon.hover.png","has_full_data":false,"large_icon":"https://s3.amazonaws.com/coursera/topics/sciwrite/large-icon.png","cats":[6,10],"unis":[1],"id":157},"160":{"insts":[2306102,2225883],"language":"en","name":"Health Informatics in the Cloud","short_name":"healthinformatics","order_idx":121,"self_service_course_id":null,"small_icon_hover":"http://coursera-course-photos.s3.amazonaws.com/58/fc257127332a300b5032649fe8e26d/logo.png","has_full_data":false,"large_icon":"http://coursera-course-photos.s3.amazonaws.com/6d/c15fdc2bc0dbbe0050b39724c7c77a/logo.png","cats":[8],"unis":[9],"id":160},"161":{"insts":[1280592,2606081],"language":"en","name":"AccountableTalk\u00ae: Conversation that Works","short_name":"accountabletalk","order_idx":122,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/42/9fd4e90a25a59232b5b07955f2b6cd/MP900422122.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/69/0a711fed1987504aec1e1adcf06094/MP900422122.jpg","cats":[6,26],"unis":[36],"id":161},"162":{"insts":[2595360,2595632],"language":"en","name":"Nutrition and Physical Activity for Health","short_name":"nutritionforhealth","order_idx":123,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/be/85a530cd01a05ba40e5a0991b3ff3a/NewNutrition-LARGE.gif","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/bb/8bbed1dc0544194f60e3cc38bec918/NewNutrition-LARGE.gif","cats":[3,19],"unis":[36],"id":162},"163":{"insts":[1564078],"language":"en","name":"A Look at Nuclear Science and Technology","short_name":"nuclearscience","order_idx":124,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/e4/95a6a83793e3a0a9162150f57c259f/MP900437258.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e4/ba69a6615c945e9e311be8fb07ce6e/MP900437258.jpg","cats":[15,23,24],"unis":[36],"id":163},"164":{"insts":[2258110,1600503],"language":"en","name":"Clinical Terminology for International and U.S. Students","short_name":"clinicalterminology","order_idx":125,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/af/07603c92e620bc12654f68844d0ae5/MP900433088.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/73/74dc188fa6f388c28b67e74362ce0f/MP900433088.jpg","cats":[3],"unis":[36],"id":164},"165":{"insts":[1722827],"language":"en","name":"Disaster Preparedness","short_name":"disasterprep","order_idx":126,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/3c/7386d7914d0c4e872a68b809d1f3d1/MP900401427.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/30/288f2ce285db9e912a165a75a55cca/MP900401427.jpg","cats":[3],"unis":[36],"id":165},"167":{"insts":[1474140],"language":"en","name":"Women and the Civil Rights Movement","short_name":"womencivilrights","order_idx":127,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9d/f8195cb776a2108bb5d7bba9be0523/banner_brown_lines.gif","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/72/8f6b8e2502675fa81c81013293b562/banner_brown_lines.gif","cats":[6],"unis":[32],"id":167},"168":{"insts":[1312728],"language":"en","name":"Developing Innovative Ideas for New Companies: The 1st Step in Entrepreneurship","short_name":"innovativeideas","order_idx":128,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/86/eff310c9f5ab16a770c3ca6c13bef3/green_courselogo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/d8/00883e52f93c47a05684f49a610437/green_courselogo.jpg","cats":[13],"unis":[32],"id":168},"170":{"insts":[324786,724736],"language":"en","name":"Exploring Quantum Physics","short_name":"eqp","order_idx":129,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/10/c8ba4de9077e632a9bd311f5323787/Preliminary_Draft_Logo_Clark_Galitski2.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c4/1c545de180c31595a29dd0f38bd7cf/Preliminary_Draft_Logo_Clark_Galitski2.png","cats":[23],"unis":[32],"id":170},"171":{"insts":[996548],"language":"en","name":"Machine Learning","short_name":"machlearning","order_idx":130,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c7/85dbfadc3808b314c25be1cb54f37a/machinelearninglogo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/29/eb5373729abeccb17eea7081421d90/machinelearninglogo.jpg","cats":[16,17],"unis":[15],"id":171},"172":{"insts":[979695,1343266],"language":"en","name":"Animal Behaviour","short_name":"animalbehav","order_idx":131,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/01/7e6485c20a9eac0e9a92c5432e8404/peacock-spider-2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/da/9a23ca374a5d18631c8f4d6b0c49d4/peacock-spider-2.jpg","cats":[10],"unis":[33],"id":172},"173":{"insts":[1288295],"language":"en","name":"Epigenetic Control of Gene Expression","short_name":"epigenetics","order_idx":132,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/a3/d40a84374147e6dcb20dc0cd458f10/Big480x270_withcopyright.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/74/92c169ff99f49dfb3136297330ccb0/Big480x270_withcopyright.jpg","cats":[3,10],"unis":[33],"id":173},"174":{"insts":[1289035],"language":"en","name":"Discrete Optimization","short_name":"optimization","order_idx":133,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/45/44e0a84be0d543937212bed01ac226/DiscreetOptimisation_logo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ca/4376935da5551984f133199185b62a/DiscreetOptimisation_logo.png","cats":[17],"unis":[33],"id":174},"175":{"insts":[937126],"language":"en","name":"Principles of Macroeconomics","short_name":"macroeconomics","order_idx":134,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/bd/5e0555c58ef27ead3a5efaccf00dca/macro_eco.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/a5/b5eac21583f1e5d7bcdb072739cea2/macro_eco.png","cats":[2],"unis":[33],"id":175},"176":{"insts":[1743955],"language":"en","name":"Software Defined Networking","short_name":"sdn","order_idx":135,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/cb/20d0eea4812003fc404b006dbe5ba0/feamstercourseimage.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e6/4d733cddcea2b35a060be49dde143f/feamstercourseimage.png","cats":[11,12],"unis":[9],"id":176},"177":{"insts":[804990],"language":"en","name":"The Modern and the Postmodern","short_name":"modernpostmodern","order_idx":136,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/40/e01a7194c35f414f37235a1a4a96e9/The-Bar-at-the-Folies-Bergeres-by-Edouard-Manet.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e5/cdbf24bfcaacee34eac286619c822b/The-Bar-at-the-Folies-Bergeres-by-Edouard-Manet.jpg","cats":[6],"unis":[34],"id":177},"178":{"insts":[1325616],"language":"en","name":"Introduction to Systems Biology","short_name":"sysbio","order_idx":137,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/73/6cd405d11bc3ff4878da9481bfc4f1/Introduction_SB_logo_460X270_v2.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b9/e9ad4b94d9f77264646f5a07436f5d/Introduction_SB_logo_460X270_v2.png","cats":[10],"unis":[27],"id":178},"179":{"insts":[1305172],"language":"en","name":"Network Analysis in Systems Biology","short_name":"netsysbio","order_idx":138,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ea/5fd940fc642a384fa660e012ee8fdf/coursera_image_maayan.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c7/e692242fb5e98d2bb83b330b6115b8/coursera_image_maayan.png","cats":[10,16,17],"unis":[27],"id":179},"181":{"insts":[1325618],"language":"en","name":"Dynamical Modeling Methods for Systems Biology","short_name":"dynamicalmodeling","order_idx":139,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/67/cd059d678aea29903129739e27addf/Dynamical_modeling_Logo_460X270_v2.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c9/6d1f5b8584be57df13528aab65576e/Dynamical_modeling_Logo_460X270_v2.png","cats":[5,10],"unis":[27],"id":181},"182":{"insts":[1297453],"language":"en","name":"Introduction to Tissue Engineering","short_name":"tissue101","order_idx":140,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/78/368a149dbfc7eaf5c69ce5164191de/husinusoid.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/72/9eb633c97aeeb24e86a3a70167bf40/husinusoid.png","cats":[10,15],"unis":[24],"id":182},"184":{"insts":[2666862,2666864,2666866,1297886,1295661],"language":"en","name":"Climate Change","short_name":"climatechange","order_idx":141,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/6f/090e9db35bd6f072a336d02e9d6794/climate_montage.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/11/a8c4ccbd5e53770228170c6ef6692a/climate_montage.jpg","cats":[2,6,25],"unis":[33],"id":184},"185":{"insts":[1298506],"language":"en","name":"Generating the Wealth of Nations","short_name":"wealthofnations","order_idx":142,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f9/1a51d965713f75f47999059c992a3d/industrial-revolution-1.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ae/74409ddd8ac19b2deab9012d03041a/industrial-revolution-1.jpg","cats":[2],"unis":[33],"id":185},"186":{"insts":[1300189],"language":"en","name":"Exercise Physiology: Understanding the Athlete Within","short_name":"exphys","order_idx":143,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/88/fcbb1591d350736d9d83e66b5a8d78/MUS-PHOTO2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b3/ded9ebdfdc70f44c67054abc3dc572/MUS-PHOTO2.jpg","cats":[3,10],"unis":[33],"id":186},"188":{"insts":[1121232],"language":"en","name":"Passion Driven Statistics","short_name":"pdstatistics","order_idx":144,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/09/ecd4e2b562e56d0499c8fadba7aa1f/passion_driven_statistics2orig.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c6/abd0e647445b20a913405180a4ebc7/passion_driven_statistics2orig.jpg","cats":[16],"unis":[34],"id":188},"189":{"insts":[1293473],"language":"en","name":"Introduction to Pharmacy","short_name":"intropharma","order_idx":145,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/78/c6efa8cac6a6f725c7ae9097e9c6bf/intro-pharm.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/27/08088f582e6ff1739181f5683a473c/intro-pharm.png","cats":[3,8],"unis":[28],"id":189},"190":{"insts":[1334447],"language":"en","name":"Principles of Public Health","short_name":"publichealth","order_idx":146,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/96/b4073c6a86832dfcd5c3ad5f3a4fac/iStock_000011822057XSmall.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/01/796e8a34fcb8d5dd688b5b3883952a/iStock_000011822057XSmall.jpg","cats":[3,8],"unis":[30],"id":190},"192":{"insts":[1293448],"language":"en","name":"Generation Rx: The Science Behind Prescription Drug Abuse","short_name":"genrx","order_idx":147,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/d9/21b6e95dc477cf495a34ea5cf5ec58/generation-rx.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/14/ad01c8627e79287de2becbda7bb474/generation-rx.png","cats":[3,8],"unis":[28],"id":192},"193":{"insts":[802670],"language":"en","name":"The Ancient Greeks","short_name":"ancientgreeks","order_idx":148,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c2/a9fe83a156d3fff4e32c6cd9caa0e5/ancientgreek.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/0e/fc442ac5d032b9e36b07b42c97ed8f/ancientgreek.jpg","cats":[6],"unis":[34],"id":193},"196":{"insts":[1292607],"language":"en","name":"Modern European Mysticism and Psychological Thought","short_name":"mysticthought","order_idx":149,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/58/e29cfad54ad288ec6c8898f29ea694/ThinkLogo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/19/eb4e2328e003742b4091e6161f8e1d/ThinkLogo.jpg","cats":[6],"unis":[24],"id":196},"197":{"insts":[1213805],"language":"en","name":"Synapses, Neurons and Brains ","short_name":"bluebrain","order_idx":150,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/1e/5f58fd74b7279b8e606d28902ad85c/logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/5c/33e98a3dbe5d21b0acc299a0a319c6/logo.jpg","cats":[10],"unis":[24],"id":197},"198":{"insts":[1234717],"language":"en","name":"Coding the Matrix: Linear Algebra through Computer Science Applications","short_name":"matrix","order_idx":151,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c9/8b3a8357fe29791971ece8cc8fb35b/460_259_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6c/ffdfc097878bc0f8115148d7ee6826/460_259_logo.jpg","cats":[1,5,16,17],"unis":[22],"id":198},"200":{"insts":[710240],"language":"en","name":"Introduction to Digital Sound Design","short_name":"digitalsounddesign","order_idx":152,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/98/a9faec3b69463938e7c7ce660e15f6/electronic_music-nologo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/16/436e7cb262ffe2571c49411810d568/electronic_music-nologo.png","cats":[18],"unis":[23],"id":200},"201":{"insts":[1324701],"language":"en","name":"Citizenship and U.S. Immigration","short_name":"immigration","order_idx":153,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/0b/5c05a126bf361e9e01b526e334bd06/immigration-nologo-2.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f7/f0a44adaf0265611da7ed6816d32b5/immigration-nologo-2.png","cats":[6],"unis":[23],"id":201},"202":{"insts":[1319386],"language":"en","name":"AIDS","short_name":"aids","order_idx":154,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7f/1ec88b36be9d908c96352c2d85da36/hiv-nologo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c7/e4f79928ef655eb6abc239078451b7/hiv-nologo.png","cats":[3,8,10],"unis":[23],"id":202},"203":{"insts":[1291950],"language":"en","name":"The Language of Hollywood: Storytelling, Sound, and Color","short_name":"hollywood","order_idx":155,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/6f/432b74de4f54bbb075c033cb9f0513/Coursera-Color-Crop.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/53/449906dea839da9dcecab59b42d8ac/Coursera-Color-Crop.jpg","cats":[6,18],"unis":[34],"id":203},"204":{"insts":[1314970],"language":"en","name":"The Fiction of Relationship","short_name":"relationship","order_idx":156,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/90/6e08b99ecc07abd5547eb019447dda/fictionimage_weinstein_rev.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/3f/b40640ec5e587fae24709f71824e9a/fictionimage_weinstein_rev.jpg","cats":[6],"unis":[22],"id":204},"205":{"insts":[1321950],"language":"en","name":"Science from Superheroes to Global Warming","short_name":"scientificthinking","order_idx":157,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/59/17e42d97116e10fe25dc71b0b2787f/460px_x_259px_female_superhero_used_for_Physics_Coursera.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/56/fbfabd3679d122b17ad4696ece54c8/460px_x_259px_female_superhero_used_for_Physics_Coursera.jpg","cats":[25],"unis":[30],"id":205},"206":{"insts":[543459],"language":"en","name":"Useful Genetics","short_name":"usefulgenetics","order_idx":158,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/3f/aab8e97db2c6c051b96d07b1c01128/Icon5cropped2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/91/1df761aaed6186f47bd741dd34cda0/Icon5cropped2.jpg","cats":[8,10],"unis":[29],"id":206},"207":{"insts":[1224295],"language":"en","name":"Archaeology's Dirty Little Secrets","short_name":"secrets","order_idx":159,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/28/d188b00f12b824cbef922191521431/archaeology-course.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/25/f5dc1d6f2eb02041e27c0f59359bab/archaeology-course.jpg","cats":[6,9,20,22,25],"unis":[22],"id":207},"208":{"insts":[1350643,1499033],"language":"en","name":"Algebra","short_name":"algebra","order_idx":160,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/bb/952409da2b5f4a9951bf89bbda646c/algebra-course-logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e0/ced6a8800e6a8eb621940ee4d03dfa/algebra-course-logo.jpg","cats":[5],"unis":[30],"id":208},"210":{"insts":[1350643,1499033],"language":"en","name":"Pre-Calculus","short_name":"precalculus","order_idx":161,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c1/32121a42fb56a015b6485d4dc37155/math1b-course-logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e5/03280804e50fee3058d12b69011a91/math1b-course-logo.jpg","cats":[5],"unis":[30],"id":210},"211":{"insts":[1324755,2598741],"language":"en","name":"Preparation for Introductory Biology: DNA to Organisms","short_name":"introbiology","order_idx":162,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/71/504df9780b5f9a22a27e64950081f8/intro-image4.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b5/35076dc6979307af0df264cafe4c15/intro-image4.jpg","cats":[10],"unis":[30],"id":211},"214":{"insts":[1466681],"language":"en","name":"Science, Technology, and Society in China I: Basic Concepts","short_name":"stschina1","order_idx":163,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/2c/3be2e63e464ca4af11330febf219dc/Naubahar-Course-Banner.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/52/0e28865ff8f0114a1558a79a1a6a26/Naubahar-Course-Banner.jpg","cats":[20],"unis":[35],"id":214},"215":{"insts":[1159084],"language":"en","name":"Sports and Society","short_name":"sports","order_idx":164,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/87/41ebab38c138ab07b95e57ae258d47/starn_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/52/64009649231929d5d7919b570b8a27/starn_logo.jpg","cats":[6,20],"unis":[7],"id":215},"216":{"insts":[1343630,1358517],"language":"en","name":"The Science of Gastronomy","short_name":"scigast","order_idx":165,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/1f/29cbc89d90f5c354bc5db353832fad/KingYeung-Course-Banner.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/d2/605f63b0878b813ed3c6c1a28ec867/KingYeung-Course-Banner.jpg","cats":[10,19],"unis":[35],"id":216},"217":{"insts":[1465513,1311294],"language":"en","name":"A New History for a New China, 1700-2000: New Data and New Methods, Part 1","short_name":"newchinahistory1","order_idx":166,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ea/835cfd8a78494dee77c26da6dccdc8/James-Course-Banner.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ec/ea4ffe0283325bef7f65e9d22612ec/James-Course-Banner.jpg","cats":[6,20],"unis":[35],"id":217},"218":{"insts":[1338423],"language":"en","name":"Introduction to Improvisation","short_name":"improvisation","order_idx":167,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/38/498a30768dadc2f431b4e906ce2d92/jazz-large.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/bb/dd4a127c81a87d90665a71334b88c0/jazz-large.jpg","cats":[18],"unis":[21],"id":218},"219":{"insts":[1338222],"language":"en","name":"Introduction to Guitar","short_name":"guitar","order_idx":168,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ee/e6e3cb2cd2ea22f792fd5126d98f7b/guitar-large.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/65/df272436bfad82debc760cb5c90ce5/guitar-large.jpg","cats":[18],"unis":[21],"id":219},"220":{"insts":[1340080],"language":"en","name":"Songwriting","short_name":"songwriting","order_idx":169,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/0c/ec10bb4adb3831a5fbbacf5ad4b47a/songwriting-large.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/24/77aee99d2b34a08a8423bc4a6178e6/songwriting-large.jpg","cats":[18],"unis":[21],"id":220},"221":{"insts":[1321389],"language":"en","name":"Property and Liability: An Introduction to Law and Economics","short_name":"lawandecon","order_idx":170,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/69/5a79fb00587dbeadb42b6dc7671ead/Smokestacks_3958.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/fc/5a1e6df000135e39d0ea2231d2ce74/Smokestacks_3958.jpg","cats":[2,6,21],"unis":[34],"id":221},"222":{"insts":[703888],"language":"en","name":"Introduction to Music Production","short_name":"musicproduction","order_idx":171,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c4/c514758cc151d86f66c9b853ec52aa/production-large.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/fe/015ba2a0d465c31b47ac36670098ea/production-large.jpg","cats":[18],"unis":[21],"id":222},"223":{"insts":[1323227],"language":"en","name":"Linear and Discrete Optimization","short_name":"linearopt","order_idx":172,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c6/0e72a56dfccc14d37aa099fac6ed12/logo_big.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/4e/c1b71842848763186f164486340b59/logo_big.png","cats":[1,5],"unis":[16],"id":223},"224":{"insts":[1325435,1325459],"language":"en","name":"Financial Engineering and Risk Management","short_name":"fe","order_idx":173,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/45/ea8f262d79710092b829d48ed3c8e1/FinacialEngLogo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/11/3ec018c6c2c88b27c587d2636462e4/FinacialEngLogo.jpg","cats":[2,16],"unis":[40],"id":224},"225":{"insts":[1325520],"language":"en","name":"Natural Language Processing","short_name":"nlangp","order_idx":174,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c5/42ab154bbf6f76f51b74b8347deab5/iStock_000020359734_Small.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/7e/0150790f6c92c48d03bf6178ea9193/iStock_000020359734_Small.jpg","cats":[17],"unis":[40],"id":225},"226":{"insts":[1342536,1989083],"language":"en","name":"Climate Literacy: Navigating Climate Change Conversations","short_name":"climateliteracy","order_idx":175,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/4a/b338570d11468050d0b64bac0adf83/Climate_Literacy-coursera-460pixels.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ec/65ea228b96d945a2bc954323b22fe3/Climate_Literacy-coursera-460pixels.jpg","cats":[20,25],"unis":[29],"id":226},"228":{"insts":[1620951,1960981,1961937],"language":"en","name":"Creative Programming for Digital Media & Mobile Apps","short_name":"digitalmedia","order_idx":176,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/6c/03b0bdb108509a7972ed079ed806c2/GoldComputing3.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/24/63a093e763b307dc9420e796aeb06a/GoldComputing3.jpg","cats":[4,12],"unis":[26],"id":228},"229":{"insts":[1330818],"language":"en","name":"Leading Strategic Innovation in Organizations","short_name":"innovation","order_idx":177,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/a5/b85c10bac7478a36397c366cff1946/Coursera-logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/21/44a0a37507298ea04382dfed448393/Coursera-logo.jpg","cats":[13],"unis":[37],"id":229},"232":{"insts":[1347691],"language":"en","name":"Malicious Software and its Underground Economy: Two Sides to Every Story","short_name":"malsoftware","order_idx":178,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/d4/edab6f88cb29582e8215774b2fa19e/cavallaro-logo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e8/06553aa034970e31d0c6372c02822e/cavallaro-logo.png","cats":[11,12],"unis":[26],"id":232},"233":{"insts":[359948],"language":"en","name":"Introduction to Systematic Program Design - Part 1","short_name":"programdesign","order_idx":179,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/35/e8609391fde9df1c434fb9ac0ee1c4/IntroSystematic_1280x720.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/78/95379b3e2298c62886f84192aaf6ee/IntroSystematic_1280x720.jpg","cats":[12],"unis":[29],"id":233},"234":{"insts":[1337829],"language":"en","name":"Pattern-Oriented Software Architectures for Concurrent and Networked Software","short_name":"posa","order_idx":180,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/6b/353126287516432c828eb1bbdb6c44/foos.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c8/1ad9b05582057b1c1caa7f9d7755fd/foos.jpg","cats":[4,11,12],"unis":[37],"id":234},"235":{"insts":[1331704],"language":"en","name":"Nutrition, Health, and Lifestyle: Issues and Insights","short_name":"lifenutr","order_idx":181,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/3d/a135768b03a37ec380ac3879dccf55/Food-icon.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/25/9fd44583ded07585d2f8ef7dad3228/Food-icon.jpg","cats":[10,19],"unis":[37],"id":235},"236":{"insts":[2330496],"language":"en","name":"Fundamentals of Human Nutrition","short_name":"humannutrition","order_idx":182,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c1/e005886ea3c68559ac0074fe7cf254/HEADHumanNutrition.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/a1/86ec691495ef1f26a1a11ba11c6f88/HEADHumanNutrition.jpg","cats":[8,10,19],"unis":[31],"id":236},"237":{"insts":[2593281],"language":"en","name":"Global Sustainable Energy: Past, Present and Future","short_name":"globalenergy","order_idx":183,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/94/1cd18dd3397e344546c0c16dbda75b/Global-Sustainable-Energy.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/4c/834e8d08a3ed98ee9ce1cec47738f0/Global-Sustainable-Energy.jpg","cats":[25],"unis":[31],"id":237},"239":{"language":"en","name":"How Music Works","short_name":"howmusicworks","order_idx":184,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/d9/dd4a66ce178e49dfd42f5728a04e53/How-Music-Works.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f9/07101b8d51ccac4ebd282d80ad8260/How-Music-Works.jpg","cats":[18],"unis":[31],"id":239},"240":{"insts":[1626852],"language":"en","name":"Sustainable Agricultural Land Management ","short_name":"sustainableag","order_idx":185,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/80/4027bdd5638b8127c2d3781317433c/Sustainable-Agriculture.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/97/a9c81f64a9c2ca4b9669df0cf8d4c3/Sustainable-Agriculture.jpg","cats":[13,19],"unis":[31],"id":240},"242":{"insts":[240569,1347429,1653154],"language":"en","name":"Data Management for Clinical Research","short_name":"datamanagement","order_idx":186,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/26/75eec287db254ae99745688463e452/data-sm.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/68/4bd7bd90bd0c84612df8a586fa1ff3/data-sm.jpg","cats":[4,16],"unis":[37],"id":242},"243":{"insts":[2603322],"language":"en","name":"Why We Need Psychology","short_name":"needpsych","order_idx":187,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/8b/337444f603516aa5f5310afc17fdae/V-multicoloured-brain.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/10/8a14cf1b5a50871e52bdd909e3612c/V-multicoloured-brain.jpg","cats":[6],"unis":[26],"id":243},"244":{"insts":[2625760],"language":"en","name":"The Camera Never Lies","short_name":"lyingcamera","order_idx":188,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/29/3c537c433a5fee786223016f6e75bf/Flag-raising-on-Iwo-Jima.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/85/c2487d4e09deb077032305464194bb/Flag-raising-on-Iwo-Jima.jpg","cats":[6,18],"unis":[26],"id":244},"245":{"insts":[2603342,3680947],"language":"en","name":"English Common Law: Structure and Principles","short_name":"engcomlaw","order_idx":189,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ce/e67b298a5c43704b0858105cc06fc0/new-logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f2/b470f53d7519ddf8511555b7cb639f/new-logo.jpg","cats":[6,21],"unis":[26],"id":245},"246":{"insts":[272543],"language":"en","name":"Online Games: Literature, New Media, and Narrative","short_name":"onlinegames","order_idx":190,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/72/9bd590fa5d2bf9bdddea3a24ad112d/Cheeryble-by-moonlight.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/50/aab96f7f0af359c5f946a1f37f2290/Cheeryble-by-moonlight.jpg","cats":[6,22],"unis":[37],"id":246},"247":{"insts":[2102206],"language":"en","name":"Economic Issues, Food & You","short_name":"ecfoodandyou","order_idx":191,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/6a/245b83c3f6e302cb3757b54fa94c1d/Eco-Issues-Food-and-You.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/55/8603642b3c5dbb3437ee5ec7e9cac0/Eco-Issues-Food-and-You.jpg","cats":[2,19],"unis":[31],"id":247},"254":{"insts":[1400787],"language":"en","name":"Foundations of Business Strategy","short_name":"strategy101","order_idx":192,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/62/ef8cb460fab1e7ed3f6ba658331ae9/Lenox-Foundations-of-Business-Strategy-460x259.gif","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/fc/bdc15b244c8a3b1c54e984576342f3/Lenox-Foundations-of-Business-Strategy-460x259.gif","cats":[13],"unis":[18],"id":254},"260":{"insts":[1292489],"language":"en","name":"MOS Transistors","short_name":"mosfet","order_idx":193,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9d/6cb1f3b5464fc65758df02e78548cb/Logo1large_b.gif","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/cd/b5dbc0f43f48a3b814c3f6177c0f66/Logo1large_b.gif","cats":[15],"unis":[40],"id":260},"268":{"insts":[1571429],"language":"en","name":"Surviving Disruptive Technologies","short_name":"sdt","order_idx":194,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ba/e3da75bef8d155a36ddb3d468b5b9f/lucas_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/cd/0c55405f6202a69f2d715e74c733b6/lucas_logo.jpg","cats":[4,13],"unis":[32],"id":268},"277":{"insts":[248242],"language":"en","name":"Principles of Microeconomics","short_name":"steinmicro","order_idx":195,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/25/a4d4bafdf99a50b9b0912510f47d42/DS_tax.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/27/9b9866d34641e63662e14bb00abdc8/DS_tax.png","cats":[2],"unis":[6],"id":277},"278":{"insts":[1127341],"language":"en","name":"Social Psychology","short_name":"socialpsychology","order_idx":196,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/e1/d3059dd666773914baa9d41fc13183/Course-Image3200x1800.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c2/67237e82ad37a8f9db40225c36935f/Course-Image3200x1800.png","cats":[8,13,14,20],"unis":[34],"id":278},"282":{"insts":[1667833],"language":"en","name":"Calculus One","short_name":"calc1","order_idx":197,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/29/7babc8e901f719a87b96d201944fd6/calculus1.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/fc/f9ebbb37faa8980a6279915601ef5b/calculus1.png","cats":[5],"unis":[28],"id":282},"285":{"insts":[2096804],"language":"en","name":"Virology I: How Viruses Work","short_name":"virology","order_idx":198,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/2a/0f2ffa0cd6cff3b083c485b94d54d7/virology_coursera.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/df/1aefaf4328c2a4ad469d8d4be6422d/virology_coursera.jpg","cats":[3,10],"unis":[40],"id":285},"288":{"insts":[1900891,2225883],"language":"en","name":"Introduction to Engineering Mechanics","short_name":"statics1","order_idx":199,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/71/4bd882b647ad3d4985c344e3bc88d3/whiteman-coursera-icon.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b2/a4e474c49efcb11c441189b12a36dc/whiteman-coursera-icon.jpg","cats":[15],"unis":[9],"id":288},"289":{"insts":[1819928],"language":"en","name":"The Law of the European Union: An Introduction","short_name":"introeulaw","order_idx":200,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/b8/1a384e65c5fc87b2383c7ec27f5f66/logo-for-the-class.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/3d/6a143d847c8040a7cb547423d6205a/logo-for-the-class.jpg","cats":[6,20,21],"unis":[25],"id":289},"290":{"insts":[1757953],"language":"fr","name":"Analyse Num\u00e9rique pour Ing\u00e9nieurs","short_name":"analysenumerique","order_idx":201,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7c/f7e490339a46553df8119142f12ad6/coursera.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c9/6b456c6bbc740fffa5f180f4276763/coursera.jpg","cats":[5,16],"unis":[16],"id":290},"292":{"insts":[1804614],"language":"en","name":"A Brief History of Humankind","short_name":"humankind","order_idx":202,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/b7/f1c2dd78e1eee4d1255aba2ac62bea/LOGO-hands-cave.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c9/598923eb2c6911166d8156eff414e3/LOGO-hands-cave.jpg","cats":[6],"unis":[24],"id":292},"293":{"insts":[2700511],"language":"en","name":"New Models of Business in Society","short_name":"bizsociety","order_idx":203,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/a4/0a3039ff90c6af9888005a3afe6cdd/Coursera-New-Models-logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ea/1871452cbd0796ceedf7e34b9ce9ab/Coursera-New-Models-logo.jpg","cats":[13,20],"unis":[18],"id":293},"295":{"insts":[1820338,1820329],"language":"en","name":"Genes and the Human Condition (From Behavior to Biotechnology)","short_name":"genes","order_idx":204,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/47/dbc72025125b1fcf426aedc02be1b4/Genes.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/a1/136c177d13b81a589adeb2bcd6f994/Genes.jpg","cats":[3,8,10],"unis":[32],"id":295},"297":{"insts":[1460],"language":"en","name":"General Game Playing","short_name":"ggp","order_idx":205,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9b/eee7cc8c0872c5e69bd0d6b7b6d81b/ggp.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/52/22e65c2ecc820ff1e6b0b42b789ab5/ggp.jpg","cats":[1,5,17],"unis":[1],"id":297},"300":{"insts":[1845856,1853352],"language":"en","name":"Startup Engineering","short_name":"startup","order_idx":206,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f0/4fba1627b59c96672c9c067eed24c0/logo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6d/36b377d4ad926485cb6342444f6743/logo.png","cats":[12,13,16],"unis":[1],"id":300},"304":{"insts":[1843870,1847439],"language":"en","name":"TechniCity","short_name":"techcity","order_idx":207,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/47/18866ac47bfe0ab4dc32b45a943837/RealTimeCity.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/27/affaf1a8cbc3f53468766a99acd35b/RealTimeCity.jpg","cats":[4],"unis":[28],"id":304},"307":{"insts":[2982963,2225883],"language":"en","name":"Introductory Physics I with Laboratory","short_name":"phys1","order_idx":208,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9c/e16ae6a09f329e67c6a0c1322d1d9f/Hero-Logo-Yellow.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/fc/88b225abb2aa2992eb147b0e23f030/Hero-Logo-Yellow.png","cats":[9,15,23,26],"unis":[9],"id":307},"311":{"insts":[1077292,2225883],"language":"en","name":"Survey of Music Technology","short_name":"musictech","order_idx":209,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/b4/a0686f1601a2634d230c4b47ffb5f9/freeman-icon.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e5/0d77b616fc55b86c82e6508cf6efa0/freeman-icon.jpg","cats":[18],"unis":[9],"id":311},"312":{"insts":[1074054,1116355,1345762],"language":"fr","name":"Initiation \u00e0 la programmation (en Java)","short_name":"intro-java-fr","order_idx":210,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/38/a24ea80f388452d9a92d0cc119295e/IMG_1575_4_3_4.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c3/fdb7ad2aca9ab2023be34c0d5bc61c/IMG_1575_4_3_4.jpg","cats":[12],"unis":[16],"id":312},"313":{"insts":[1116355,1345762,1074054],"language":"fr","name":"Initiation \u00e0 la programmation (en C++)","short_name":"intro-cpp-fr","order_idx":211,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/41/c05a717c0efe8aeaf17e7a49ec4eaf/IMG_1565_4_5.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/34/05fae9c412b2005e0b9ec12d956017/IMG_1565_4_5.jpg","cats":[12],"unis":[16],"id":313},"314":{"insts":[1074054,1116355,1345762],"language":"fr","name":"Introduction \u00e0 la programmation orient\u00e9e objet (en C++)","short_name":"cpp-fr","order_idx":212,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ce/fbc94504d53fbb5a70aa20fcad7b34/IMG_1576_2_2_4.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c8/5909f63e233b0a7fb3e10bccd85edb/IMG_1576_2_2_4.jpg","cats":[12],"unis":[16],"id":314},"315":{"insts":[2666378,2996815],"language":"en","name":"\"Pay Attention!!\" ADHD Through the Lifespan","short_name":"adhd","order_idx":213,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ce/f2950e11c1c191eaffcbf4f4cfc213/ADHD_brain.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/57/7dbae9df0fca1b8f216d9ae6f127ec/ADHD_brain.jpg","cats":[3],"unis":[6],"id":315},"322":{"insts":[2606554,2225883],"language":"en","name":"Introduction to Psychology as a Science","short_name":"psy","order_idx":214,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/15/9c0d5abfbc092928a2e53de58e901c/smith-course-icon.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/09/a86f1d8786b6c5bb04b5920b174f84/smith-course-icon.png","cats":[20],"unis":[9],"id":322},"327":{"insts":[1462466],"language":"en","name":"English Composition I: Achieving Expertise","short_name":"composition","order_idx":215,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/30/858861451d5799f69c4c41629034f2/wordlemap.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/d7/0b0fec4bac0eb2c60314224f8b53a1/wordlemap.png","cats":[6,14,20],"unis":[7],"id":327},"328":{"insts":[1915980],"language":"en","name":"Introduction to Psychology","short_name":"intropsych","order_idx":216,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/a7/8e50c11598003ad1a2fd27999ec76f/iStock_000002041388_ExtraSmall.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/93/0ff63800e8b878da89ca45006bd392/iStock_000002041388_ExtraSmall.jpg","cats":[20],"unis":[11],"id":328},"329":{"insts":[1084582,2068199],"language":"en","name":"Statistics: Making Sense of Data","short_name":"introstats","order_idx":217,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/b6/72346c65a58cb9796713fe3bcdee3f/introstatslogocropped.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b3/bbb02469fea71f12557d5258cccd5a/introstatslogocropped.jpg","cats":[16],"unis":[11],"id":329},"333":{"insts":[2468250,2225883],"language":"en","name":"Games without Chance: Combinatorial Game Theory ","short_name":"cgt","order_idx":218,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/87/625c24789637a36ebdb36f0927702d/morley-icon.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f7/101b7bc269afd0575ad20bcef8fcc7/morley-icon.jpg","cats":[5],"unis":[9],"id":333},"334":{"insts":[2594168],"language":"en","name":"Corporate Finance","short_name":"finance","order_idx":219,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/74/3653210f1dfc9c38af58f171127860/coursera_finance_460x259.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b3/83961fd6f3d1c2f820fafed3f75b7a/coursera_finance_460x259.png","cats":[2,13],"unis":[6],"id":334},"337":{"insts":[2093911],"language":"en","name":"Big Data in Education","short_name":"bigdata-edu","order_idx":220,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/0f/daf5f9cde97c3372fdbcc5a4d44a26/chico-compy-v2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f3/82573d90d69ae4a51c2c4ce8d6ba3c/chico-compy-v2.jpg","cats":[14,16],"unis":[40],"id":337},"347":{"insts":[1505164,2041603,1957524,2029839,1893981],"language":"en","name":"Writing II: Rhetorical Composing","short_name":"writing2","order_idx":221,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/6b/d0dcfdbd4dbdde7216fc9d67c2b6d4/Writing2-Rhetorical-Composing.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f9/2565dae921183950deb6b9194c060d/Writing2-Rhetorical-Composing.jpg","cats":[6,14],"unis":[28],"id":347},"354":{"insts":[1894245],"language":"en","name":"The Global Business of Sports","short_name":"globalsportsbusiness","order_idx":222,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9d/d10a1390c031cd40168543b8d3dae8/GBS.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/74/81ca08db4507957f5824f13052615c/GBS.jpg","cats":[13,20],"unis":[6],"id":354},"356":{"insts":[1937011],"language":"en","name":"An Introduction to Financial Accounting","short_name":"accounting","order_idx":223,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/a8/ba23a7f13d9e874afa6bdb57eabc3c/coursera_accounting_460x259.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/81/df41595ce06513117e550aca792344/coursera_accounting_460x259.png","cats":[2,13],"unis":[6],"id":356},"357":{"insts":[3237389],"language":"en","name":"Caries Management by Risk Assessment (CAMBRA)","short_name":"cariesmanagement","order_idx":224,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/e1/ef87539b4b04d28363c65aa39aa741/newlogo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/21/7006dc0e394b4cd80a7d1283ab9d87/newlogo.jpg","cats":[3,8,10],"unis":[10],"id":357},"367":{"insts":[2526797],"language":"en","name":"Computational Molecular Evolution","short_name":"molevol","order_idx":225,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/4c/7b8be574c6d1d4eecbf766fb41ce9a/green_lime4.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/3b/f49feb83ae9131afb90d59db8a37cf/green_lime4.png","cats":[10,16],"unis":[57],"id":367},"368":{"insts":[2589497,2589622],"language":"zh-Hant","name":"The Beauty of Kunqu Opera | \u5d11\u66f2\u4e4b\u7f8e","short_name":"kunqu","order_idx":226,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ba/739cf02190b08eb02167959e636649/banner_kq.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/47/3dbae8eb937b30a97e47b15eb384ea/banner_kq.jpg","cats":[22],"unis":[45],"id":368},"369":{"insts":[2589075,2589701],"language":"zh-Hant","name":"Classics of Chinese Humanities: Guided Readings | \u4e2d\u570b\u4eba\u6587\u7d93\u5178: \u5927\u5e2b\u5c0e\u8b80","short_name":"chinesehumanities","order_idx":227,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/be/65d767d3d99cb577636f93b54b7ff2/humanities.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e5/66d0de2e961f1e3b9787e892e85495/humanities.jpg","cats":[6],"unis":[45],"id":369},"371":{"insts":[2789426,2947873],"language":"en","name":"Growing Old Around the Globe","short_name":"oldglobe","order_idx":228,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/53/36cef703d4a37e05a571326d4e7d98/Kagan-Intro-fancy-back-16.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e4/dab967e22d1600a37c14a4558eb802/Kagan-Intro-fancy-back-16.png","cats":[3,8],"unis":[6],"id":371},"376":{"insts":[640270],"language":"en","name":"Introduction to Classical Music","short_name":"introtoclassical","order_idx":229,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c3/41d8a7942b594d66989479c9c9bb20/introtoclassical_Logo_3.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/76/90e1775c6495b5d260e24780837e61/introtoclassical_Logo_3.jpg","cats":[18],"unis":[3],"id":376},"378":{"insts":[289468,2480111],"language":"en","name":"Drug Discovery, Development & Commercialization ","short_name":"drugdiscovery","order_idx":230,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7f/df3d33134a11d893ea8dc861ff0b88/IR.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/83/66951066de213da55bf8eb5ef234ae/IR.jpg","cats":[3,10],"unis":[53],"id":378},"380":{"insts":[2605293],"language":"en","name":"Social Epidemiology","short_name":"socialepi","order_idx":231,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/e5/d83d65ee86e54f915a1b211cbe2d76/Final-Social-Epidemiology-.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/d1/356a4ab3519b9b7bab0f1bc9c9813b/Final-Social-Epidemiology-.jpg","cats":[8,20],"unis":[50],"id":380},"381":{"insts":[2601001],"language":"en","name":"Statistical Molecular Thermodynamics","short_name":"thermodynamics","order_idx":232,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/50/edb5a49f0b862b982b945e54e4406e/Final-Train.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/3d/2829770e40c961a1b3b7c7e7fbbae0/Final-Train.png","cats":[24],"unis":[50],"id":381},"382":{"insts":[2608269],"language":"en","name":"Interprofessional Healthcare Informatics","short_name":"newwayhealthcare","order_idx":233,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/49/392534d539814315e4ac197f672980/Final-Health-Informatics.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/41/a5f93b29848fe1bcb8ee8c30bbdd1f/Final-Health-Informatics.jpg","cats":[4,8,20],"unis":[50],"id":382},"383":{"insts":[2570343],"language":"en","name":"Sustainability of Food Systems: A Global Life Cycle Perspective","short_name":"globalfoodsystems","order_idx":234,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/72/020dd47bdf806d546cd7d9553fa18f/large.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/44/e431f018d3e315b325966667622c56/large.jpg","cats":[2,19,25],"unis":[50],"id":383},"384":{"insts":[2042576],"language":"en","name":"Introduction to Thermodynamics: Transferring Energy from Here to There","short_name":"introthermodynamics","order_idx":235,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f2/ddf57c345af5127a678f07275430a3/bigstockphoto_Gas_Energy_Flames_209173_EDIT.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/64/d7db712c29c68f4db6970f5073d972/bigstockphoto_Gas_Energy_Flames_209173_EDIT.jpg","cats":[15,25],"unis":[3],"id":384},"385":{"insts":[2408877,2604148,2513105,2590461],"language":"fr","name":"Calvin - Histoire et R\u00e9ception d'une R\u00e9forme","short_name":"calvin","order_idx":236,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/dc/f06ad4d4410fb8b0f8a75004f7e393/Calvin.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/9b/74b1b58f6ad5183a369ef568aaad29/Calvin.jpg","cats":[6],"unis":[49],"id":385},"386":{"insts":[2566087],"language":"en","name":"An Introduction to Global Health","short_name":"globalhealthintro","order_idx":237,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/29/2943e86130339267b8e0212a6b2f60/global_health.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/60/b605b8984a47079e220eda9c2a6527/global_health.jpg","cats":[3,8,19,20],"unis":[63],"id":386},"391":{"insts":[323100],"language":"es","name":"Ser m\u00e1s creativos","short_name":"creatividad","order_idx":238,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/86/a32252dc32bc8456ce54b23d86afdf/20130416.elefante_ser_creativo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/47/7040d863b423ee131be97317f830f9/20130416.elefante_ser_creativo.jpg","cats":[4,6,14,20],"unis":[58],"id":391},"393":{"insts":[2606384],"language":"en","name":"Canine Theriogenology for Dog Enthusiasts","short_name":"theriogenology","order_idx":239,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/87/69cc05ef12e4982b4d90b053661f73/Therio-logo.gif","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6b/522d9d2e33a8aad60cef459d284d10/Therio-logo.gif","cats":[3,8,10],"unis":[50],"id":393},"394":{"insts":[1252],"language":"en","name":"Social and Economic Networks: Models and Analysis","short_name":"networksonline","order_idx":240,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/1a/0fd0bcaded566342c65e16db568094/Logo1.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/1c/38d188bf97105025168a55aebc634a/Logo1.jpg","cats":[1,2,5,16,20],"unis":[1],"id":394},"398":{"insts":[2566181],"language":"en","name":"Constitutional Struggles in the Muslim World","short_name":"muslimworld","order_idx":241,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/3e/22a29f09a881794a9ac7fa82451aaf/muslim_democracy.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/45/ae92b8fc5d4629a785785e01599a9d/muslim_democracy.jpg","cats":[6,20,21],"unis":[63],"id":398},"399":{"insts":[2579174,2558013],"language":"en","name":"Diabetes - a Global Challenge","short_name":"diabetes","order_idx":242,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/22/ac401bc393817f41889a8579a05646/diabetes.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/63/d179e5336202b41c3132363fef3854/diabetes.jpg","cats":[3,8,10],"unis":[63],"id":399},"400":{"insts":[2500042],"language":"en","name":"Scandinavian Film and Television","short_name":"scanfilmtv","order_idx":243,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/76/691bbbbdc23d7d44bdad9fda989993/scandinavian_film.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ba/3c3c20f06dcd7b998519c5ed9925ce/scandinavian_film.jpg","cats":[6,18],"unis":[63],"id":400},"401":{"insts":[2566619],"language":"en","name":"Measuring Causal Effects in the Social Sciences","short_name":"causaleffects","order_idx":244,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ff/c2d28733fdbdfefcd5f7eb5330fe42/social_science.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/bf/793760af781056e40aa8cc0598c991/social_science.jpg","cats":[20],"unis":[63],"id":401},"402":{"insts":[2619522],"language":"en","name":"S\u00f8ren Kierkegaard - Subjectivity, Irony and the Crisis of Modernity","short_name":"kierkegaard","order_idx":245,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/bb/98b4193b2f80f2773d9308992cb490/kirkegaard.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b4/dd0b26c2c7f9464fb54a52a9061579/kirkegaard.jpg","cats":[6],"unis":[63],"id":402},"403":{"insts":[2428255],"language":"en","name":"Origins - Formation of the Universe, Solar System, Earth and Life","short_name":"origins","order_idx":246,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f4/f504a44e76b468dc3633411e751534/origins.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/73/6f85b09ed59dcb2ab9b257d9741e0a/origins.jpg","cats":[10,23],"unis":[63],"id":403},"404":{"insts":[2569351],"language":"en","name":"The New Nordic Diet - from Gastronomy to Health ","short_name":"newnordicdiet","order_idx":247,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/b4/44fcff14303f44e26f62f66889acf3/nordic_food.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/86/1810f425e9ef884db01f81c65b8995/nordic_food.jpg","cats":[8,10,19],"unis":[63],"id":404},"405":{"insts":[2600270,2600267],"language":"en","name":"The Role of the Renminbi in the International Monetary System","short_name":"renminbi","order_idx":248,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c8/b199d583361630a91b76d8db680daa/renminbi.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/35/1e610f6d0e35718df80bb74d9a16b4/renminbi.jpg","cats":[2],"unis":[45],"id":405},"407":{"insts":[2600275],"language":"en","name":"Information Theory","short_name":"informationtheory","order_idx":249,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/fc/e01b933fb99fc2bec4e9a9b4a4e9eb/informationtheory.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/92/9a1dd0e06140d3c9cd15748f7e5290/informationtheory.jpg","cats":[4],"unis":[45],"id":407},"408":{"insts":[1177458],"language":"es","name":"Tecnolog\u00edas de informaci\u00f3n y comunicaci\u00f3n en la educaci\u00f3n","short_name":"ticyeducacion","order_idx":250,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/16/543cadb9465e61a6bb14fa5cf6099c/20130214.logo.curso.tic.en.educacin.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b6/4b34e36ceed9df4163b9fb5d54607c/20130214.logo.curso.tic.en.educacin.jpg","cats":[14],"unis":[58],"id":408},"409":{"insts":[2320972],"language":"en","name":"C++ For C Programmers","short_name":"cplusplus4c","order_idx":251,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/a8/5c08c3733378cb0084b2d43366edd3/Cplusplus_pic.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/fa/d7bcd2453f7664b9dd47c6f4c78c91/Cplusplus_pic.jpg","cats":[12],"unis":[56],"id":409},"410":{"insts":[625560],"language":"en","name":"Children Acquiring Literacy Naturally","short_name":"childliteracy","order_idx":252,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/02/a05c0435a3c4d6c96d4b627fcb5e1c/Slide1.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6c/a791d9fcf4f0d1afdfbd3b93e198b7/Slide1.jpg","cats":[4,14,20],"unis":[56],"id":410},"411":{"insts":[2395490],"language":"en","name":"Child Nutrition and Cooking","short_name":"childnutrition","order_idx":253,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9f/77585588b3e0b1e7fab3a643888652/Just-Cook-Logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/45/16242684977f84465bfbb83aebc1b2/Just-Cook-Logo.jpg","cats":[3,8,14,19],"unis":[1],"id":411},"413":{"insts":[2533383],"language":"es","name":"Pensamiento Cient\u00edfico","short_name":"ciencia","order_idx":254,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/5c/84603b32f215814dd5b0ab63cd4738/20130218.logo.curso.pensamiento.cientfico.amarillo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6a/126151ccb882df4e97b11745919882/20130218.logo.curso.pensamiento.cientfico.amarillo.jpg","cats":[6,10],"unis":[58],"id":413},"415":{"insts":[2683483],"language":"en","name":"International Organizations Management","short_name":"interorg","order_idx":255,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/d4/f80d67c9ef2aac0c8ce9982f95e43f/IO-Management.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/3b/0dc41ff85d3597adfe26119754dc4e/IO-Management.jpg","cats":[13],"unis":[49],"id":415},"417":{"insts":[2650854],"language":"en","name":"Introduction to Art: Concepts & Techniques","short_name":"art","order_idx":256,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/89/44276eb7cf6defe93fdf57dff28b28/art10_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/a4/4b9e1c8f528199e60e6240e8e76721/art10_logo.jpg","cats":[6,22],"unis":[51],"id":417},"418":{"insts":[2560495],"language":"en","name":"Maps and the Geospatial Revolution","short_name":"maps","order_idx":257,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/8e/07b7e6bc9d0b1e178eebcf939c1172/MapsGR_Logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/5d/d09bd4de6f923c96083e1fe8d91075/MapsGR_Logo.jpg","cats":[4,16,20],"unis":[51],"id":418},"419":{"insts":[1924714,2644910,2631338],"language":"en","name":"Creativity, Innovation, and Change","short_name":"cic","order_idx":258,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7f/56693aa548f9e1e83f3e4fb231b799/CIC_MOOC_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ce/45bcd7952fd6a4170188f0c9056e0a/CIC_MOOC_logo.jpg","cats":[4,13,14,15,20],"unis":[51],"id":419},"420":{"insts":[72633,2687735,2687745,2687752,2687763,2687771,2687778,2687782],"language":"en","name":"Epidemics - the Dynamics of Infectious Diseases","short_name":"epidemics","order_idx":259,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/d7/f83ea9bd261a073200c05bd894d6cf/infectiousdisease-MOOC.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f2/36713ca852484ffad471b5d22e2efd/infectiousdisease-MOOC.png","cats":[8,10],"unis":[51],"id":420},"421":{"insts":[2645422],"language":"en","name":"Energy, the Environment, and Our Future","short_name":"energy","order_idx":260,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/94/0f7575f2bc66c8f2f8ee1a540e095e/alley_energy_course_graphic.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c9/2d9784b2f32b5280bf5fc352dfaee9/alley_energy_course_graphic.jpg","cats":[25],"unis":[51],"id":421},"422":{"insts":[2589160,2588904],"language":"en","name":"The Holocaust","short_name":"holocaust","order_idx":261,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/79/6f09ed01c62a32881de83b58ba7a0a/g31j.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/20/0159d0b81938d4828dc0f13cbd1d6d/g31j.jpg","cats":[6],"unis":[56],"id":422},"425":{"insts":[2605756],"language":"en","name":"Human Evolution: Past and Future","short_name":"humanevolution","order_idx":262,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/4c/de0fc51308f7dedd6a3e06012cc61f/amud-ohalo-vienna.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/4a/14fb96da2a865e6b4f71fe8beb1181/amud-ohalo-vienna.jpg","cats":[10,20],"unis":[65],"id":425},"426":{"insts":[2605719,2605744],"language":"en","name":"Videogames and Learning","short_name":"videogameslearning","order_idx":263,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/bd/0b35c09d33803063c664ea185ea121/games_learn.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/70/300d2249f91fd85aedc2a1ea49ba9c/games_learn.jpg","cats":[4,14],"unis":[65],"id":426},"427":{"insts":[2605731,2687823],"language":"en","name":"Globalizing Higher Education and Research for the \u2018Knowledge Economy\u2019","short_name":"globalhighered","order_idx":264,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/18/51bebaa24f4e80852f271d5498d998/TwitterAvatar.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ca/74dfc7e9fe83fc00f4f37878a6e030/TwitterAvatar.jpg","cats":[4,14,20],"unis":[65],"id":427},"428":{"insts":[2605772],"language":"en","name":"Markets with Frictions","short_name":"marketswithfrictions","order_idx":265,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/b3/5e4552e4555556067af9aed4aa98c5/markets.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e4/133081d7a5a15c59c924ce20160da6/markets.jpg","cats":[2,13],"unis":[65],"id":428},"429":{"insts":[2276941],"language":"en","name":"Case-Based Introduction to Biostatistics","short_name":"casebasedbiostat","order_idx":266,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/bb/b6ac6b15812763f392fd0d4b60fb4c/case_based_mag_glass-01.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/43/6f96f6c5e26cfe862b3acb6da4591e/case_based_mag_glass-01.png","cats":[8,16],"unis":[8],"id":429},"430":{"insts":[2511245,2894378,3096301,2581715,2590328,2918070],"language":"en","name":"Global Health: Interdisciplinary Overview","short_name":"globalhealthoverview","order_idx":267,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/fa/f06d98e0b774e79a3607b6d6802969/GlobalHealth.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/44/56963ae7fbfa6e19ecb56ad20ed4e3/GlobalHealth.jpg","cats":[3,8],"unis":[49],"id":430},"431":{"insts":[2359335,2204104],"language":"en","name":"Fundamentals of Audio and Music Engineering: Part 1 Musical Sound & Electronics","short_name":"audiomusicengpart1","order_idx":268,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ba/359ae379570a70ecc45e6efcc49447/FundamentalsSound_ImageLogo-3.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/1d/b3aaaad0e4ab67581f1e4b664efc6c/FundamentalsSound_ImageLogo-3.jpg","cats":[15,18],"unis":[60],"id":431},"432":{"insts":[2512709,2582502],"language":"en","name":"Introduction to Mathematical Philosophy","short_name":"mathphil","order_idx":269,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/27/0c882ed4049498e49834ff054421b6/LogoMathPhil11.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/46/73a43c2b90d50c70a211d868a46f22/LogoMathPhil11.jpg","cats":[5,6],"unis":[64],"id":432},"433":{"insts":[2582522],"language":"en","name":"Programmed cell death","short_name":"pcd","order_idx":270,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/77/9eb8e03c1d2ccc33d0bd44ee826db2/pcd-001-Logo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/61/d69590aa893335e7c9f568ffd39c8e/pcd-001-Logo.png","cats":[3,10],"unis":[64],"id":433},"434":{"insts":[2602668],"language":"zh-Hant","name":"\u6a5f\u7387","short_name":"prob","order_idx":271,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/03/830f868afe29991b76b62550f00e0c/iStock_000000248160_Small.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b2/b093a008006adfe6424db3a1b17869/iStock_000000248160_Small.jpg","cats":[5,15],"unis":[75],"id":434},"435":{"insts":[2599979],"language":"en","name":"History of Rock, Part One","short_name":"historyofrock1","order_idx":272,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/46/c0d3b9366726f25f501b4815bfffdb/HistoryofRockLogo2pt1.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/1c/3ac4701bb77ecf9be973ae7a07dfd8/HistoryofRockLogo2pt1.jpg","cats":[18],"unis":[60],"id":435},"436":{"insts":[2506410],"language":"en","name":"Design Thinking for Business Innovation","short_name":"designbiz","order_idx":273,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f8/0fda7e21538899bc3f48391f72f1d2/DatD_Coursera.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/5b/e90b07f9b99d0b23f23d9c949ad68d/DatD_Coursera.png","cats":[13],"unis":[18],"id":436},"438":{"insts":[2580055,2593202],"language":"fr","name":"Initiation \u00e0 la th\u00e9orie des distributions","short_name":"distributions","order_idx":274,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/76/e5970454f7eb2a6d3c9f07d29f755a/logg.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/9d/722d663f5f711fa3a61c8f7db89deb/logg.jpg","cats":[5],"unis":[66],"id":438},"439":{"insts":[2333330],"language":"en","name":"Foundations of Virtual Instruction","short_name":"virtualinstruction","order_idx":275,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c3/2210e94025c8da7f8072890c9b40ad/Virtual-Instruction-Logo_Correct-Size.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/1d/809b47eec770ec1ec8bcc871b8423e/Virtual-Instruction-Logo_Correct-Size.jpg","cats":[4,14,26],"unis":[30],"id":439},"440":{"insts":[2599979],"language":"en","name":"History of Rock, Part Two","short_name":"historyofrock2","order_idx":276,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/8c/8e98e44a27a0a6dc0d25393c73bf57/HistoryofRockLogo2pt2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/de/a1fa5dad47723b1b1523cba8f9adb2/HistoryofRockLogo2pt2.jpg","cats":[18],"unis":[60],"id":440},"441":{"insts":[2089332],"language":"en","name":"Live!: A History of Art for Artists, Animators and Gamers","short_name":"livearthistory","order_idx":277,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/3d/8f940bd5406c96550d54e2825afb3c/JEANNENE_P.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/58/351265b97720115d956670f3bb1794/JEANNENE_P.jpg","cats":[6,18,22],"unis":[59],"id":441},"442":{"insts":[2531752],"language":"en","name":"Creating Site-Specific Dance and Performance Works","short_name":"sitedance","order_idx":278,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/d7/9d7d396bfc35bdf06530423edcdcca/STEPHAN_K.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e9/bfb17bca07d0a30a12ac5c31774aed/STEPHAN_K.jpg","cats":[22],"unis":[59],"id":442},"443":{"insts":[2660238],"language":"en","name":"Introduction to Programming for Musicians and Digital Artists","short_name":"chuck101","order_idx":279,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/da/e6b40618a9d340bce35221ad5f17a9/logo.gif","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/15/f9b67ffb18278fe22f34c30d4c780d/logo.gif","cats":[12,18,22],"unis":[59],"id":443},"445":{"insts":[981331],"language":"zh-Hans","name":"Structural Equation Model and its Applications | \u7ed3\u6784\u65b9\u7a0b\u6a21\u578b\u53ca\u5176\u5e94\u7528","short_name":"sem","order_idx":280,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/20/d1c7f9eb983b85924159a121793121/banner_n.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/4a/044557d6c10a674cf89ec22699d02e/banner_n.jpg","cats":[14,16,20],"unis":[45],"id":445},"446":{"insts":[2423001,1622801],"language":"fr","name":"Conception et mise en oeuvre d'algorithmes.","short_name":"algoprog","order_idx":281,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/71/ffe71b46e9a30beeb03cd38cdd6450/logo3.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/58/919b5d0ca0f0b15ef00cc985b2dfaf/logo3.jpg","cats":[1],"unis":[66],"id":446},"447":{"insts":[1914201,2593255],"language":"fr","name":"Al\u00e9atoire : une Introduction aux Probabilit\u00e9s ","short_name":"probas","order_idx":282,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c9/ba837facca9cd9d4f5636600ea2910/logo-0.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ab/adb7827745efc2137c916d1f4ac75fe8/logo-0.jpg","cats":[5],"unis":[66],"id":447},"448":{"insts":[2635797,2642321],"language":"en","name":"Law and the Entrepreneur ","short_name":"law","order_idx":283,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/11/d6c0b84697d4df4b37b58e081c0548/lawmooc-image.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/16/91f9f9999e708b3da8ea89cfe4ee96/lawmooc-image.jpg","cats":[13,21],"unis":[54],"id":448},"449":{"insts":[1166989],"language":"en","name":"Antimicrobial Stewardship: Optimization of Antibiotic Practices","short_name":"antimicrobial","order_idx":284,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/fd/1229a4ddcdf524e45be633e899eb5b/penicillin-vials_small.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/d3/26b05232873dabe4672f5778943a28/penicillin-vials_small.jpg","cats":[3],"unis":[1],"id":449},"450":{"insts":[2633312],"language":"en","name":"Recovering the Humankind Past and Saving the Universal Heritage","short_name":"recoveringthepast","order_idx":285,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/8f/1fb089cd8f28b9e7a8f3cc80b2cb05/Matthiae_Ebla.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/eb/36301e697e4cf40cbfc73dafd118be/Matthiae_Ebla.jpg","cats":[6],"unis":[74],"id":450},"451":{"insts":[2641217],"language":"en","name":"Terrorism and Counterterrorism: Comparing Theory and Practice","short_name":"terrorism","order_idx":286,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/37/25873c28b5a43aa53d454cba0dbf75/Terrorism-and-Counterterrorism.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/69/64180fe480055ce3b330c20ffc91f8/Terrorism-and-Counterterrorism.jpg","cats":[6,20],"unis":[25],"id":451},"453":{"insts":[2691794],"language":"en","name":"Understanding Einstein: The Special Theory of Relativity","short_name":"einstein","order_idx":287,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7f/cf6ce352318cad440898a2be0b138a/iStock_000018822031Small.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c5/cbbe26c2d530d744a4b04f2f41cae8/iStock_000018822031Small.jpg","cats":[6,23],"unis":[1],"id":453},"455":{"insts":[2644105],"language":"zh-Hant","name":"\u4e2d\u570b\u53e4\u4ee3\u6b77\u53f2\u8207\u4eba\u7269\uff0d\uff0d\u79e6\u59cb\u7687","short_name":"chinesehistory","order_idx":288,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/86/d330001204e7140582f65a9e6e9478/A.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/0c/b9777acfb9354116c24f5c6c0c8a85/A.jpg","cats":[6],"unis":[75],"id":455},"456":{"insts":[2645301,2645318],"language":"en","name":"Soul Beliefs: Causes and Consequences","short_name":"soulbeliefs","order_idx":289,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/71/222b0df7612fb28c3fd36cfebf1957/BD_Mummy_and_Ba.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/73/a6fe18dbaaba26c95aa2ea00b0be1a/BD_Mummy_and_Ba.jpg","cats":[6,20],"unis":[67],"id":456},"457":{"insts":[2340295],"language":"en","name":"Confronting The Big Questions: Highlights of Modern Astronomy","short_name":"astronomy","order_idx":290,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/bd/49a04294a993b0141690788ab2f6f2/HighlightsAstronomyLogo-2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/4d/b707024cb3250d4f55399fac84ee96/HighlightsAstronomyLogo-2.jpg","cats":[23],"unis":[60],"id":457},"458":{"insts":[2645257,2645262],"language":"es","name":"Innovaci\u00f3n educativa con recursos abiertos","short_name":"innovacionrea","order_idx":291,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7b/3529cd506ad9017acebd6e251de26c/coursera_001_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b9/28895749944f002a0fd6d42f8716e9/coursera_001_logo.jpg","cats":[14],"unis":[62],"id":458},"459":{"insts":[2573718],"language":"en","name":"Competitive Strategy","short_name":"compstrategy","order_idx":292,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/41/569c7574095ce7f5ec3b012380709f/tic_tac_toe_iStock_Natasha-Japp-Photography_webl.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ac/57b21e8a5cc489a45ebfc4200aaf1e/tic_tac_toe_iStock_Natasha-Japp-Photography_webl.png","cats":[2,13],"unis":[64],"id":459},"460":{"insts":[2595276],"language":"en","name":"Understanding economic policymaking","short_name":"econpolicy","order_idx":293,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/67/ccafab4a7fb4608a5bfa179d1edecb/5course_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/5b/f936f9d62617bd33b6ac7f9f704161/5course_logo.jpg","cats":[2],"unis":[61],"id":460},"461":{"insts":[2633310],"language":"it","name":"La visione del mondo della Relativit\u00e0 e della Meccanica Quantistica","short_name":"rqm","order_idx":294,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ca/fdede07dfdc8736b57af429144682d/logo-RQM-4-1-liv.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/7b/726abddcdeb722eb183057e5109a01/logo-RQM-4-1-liv.jpg","cats":[6,23],"unis":[74],"id":461},"462":{"insts":[2650348],"language":"en","name":"Analyzing the Universe","short_name":"analyze","order_idx":295,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/22/26e686620527dc5aa46036d2915047/supernova-black-hole.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e0/0ca6c0356518a9bb53d5de418c54db/supernova-black-hole.jpg","cats":[23],"unis":[67],"id":462},"463":{"insts":[2075897],"language":"en","name":"Inspiring Leadership through Emotional Intelligence","short_name":"lead-ei","order_idx":296,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ec/846ea70a3c01d0b3ae27ad125023f3/147669568.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/27/fd5ca575e9b7dde1ba926b5b8546aa/147669568.jpg","cats":[13,14,20],"unis":[68],"id":463},"464":{"language":"es","name":"El ABC del emprendimiento esbelto ","short_name":"abcemprendimiento","order_idx":297,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/cd/4887d61f3cc9c8a8d88a830ad46f37/coursera_002_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b9/402975b12d04fee63b14accf290816/coursera_002_logo.jpg","insts":[2645282,3231512,2747070],"unis":[62],"id":464},"465":{"insts":[2602095],"language":"en","name":"Volcanic Eruptions: a material science.","short_name":"volcano","order_idx":298,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/4a/dfa944049fdefa48235e1017c08cbb/vulkan_ammit_istock_webl.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ed/9ad5267c53b591430153ba14138982/vulkan_ammit_istock_webl.png","cats":[9,25],"unis":[64],"id":465},"466":{"insts":[2527015],"language":"en","name":"Introduction to International Criminal Law","short_name":"intlcriminallaw","order_idx":299,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/79/2f60b9be37a48e95889e4bde705b0b/Untitled.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/cd/0aa55e6a5e2f7280d4e32064c81199/Untitled.png","cats":[21],"unis":[68],"id":466},"467":{"insts":[2633305],"language":"en","name":"Early Renaissance Architecture in Italy: from Alberti to Bramante","short_name":"renaissancearchitect","order_idx":300,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9a/6e4051c4442cd25c8e448634d18c04/77650945.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/73/c17dacf21ef571074062b31b6de890/77650945.jpg","cats":[6,22],"unis":[74],"id":467},"469":{"insts":[2653254,2653304,2191978],"language":"en","name":"Crafting an Effective Writer: Tools of the Trade","short_name":"basicwriting","order_idx":301,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/06/41cc053e58c65b59e03e3b67c1e30b/msjc.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/bd/c650a4feea8765e09f7045f205649b/msjc.jpg","cats":[6],"unis":[44],"id":469},"471":{"insts":[1540981,2658887,3542322],"language":"en","name":"Bioinformatics Algorithms (Part 1) ","short_name":"bioinformatics","order_idx":302,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/58/fc2352270af701c467c03792e93a5b/Bioinf.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c7/be0dd407562e5c562e97a0f3b79a6e/Bioinf.png","cats":[1,10],"unis":[53],"id":471},"472":{"insts":[2656811],"language":"en","name":"Critical Perspectives on Management","short_name":"criticalmanagement","order_idx":303,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/b9/c82d88b9a0aa3b024d98cbf7cfa9b7/managemen_logot.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/4b/3da2bbd8abdaeb9907476a6c4d82f5/managemen_logot.jpg","cats":[13],"unis":[61],"id":472},"474":{"insts":[2657356],"language":"en","name":"Understanding Media by Understanding Google","short_name":"googlemedia","order_idx":304,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9d/32ba053bf45ecdf427b9c640820585/photo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/15/47950012e5694839aca29b8d5dbb30/photo.jpg","cats":[2,4,13],"unis":[54],"id":474},"475":{"insts":[2659612],"language":"en","name":"Introduction to Power Electronics","short_name":"powerelectronics","order_idx":305,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/1b/40b383b0d0d0dfbe9eed8008649a61/image.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/1c/110aebe42e22a214b71f2b2a3a2529/image.jpg","cats":[15],"unis":[71],"id":475},"476":{"insts":[2645293],"language":"en","name":"Latin American Culture","short_name":"latinamericanculture","order_idx":306,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7a/c25b15b1e04fe5224d2d97cfd0411e/coursera_003_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/dd/5bb05a4f43c860638d065f0131d9d1/coursera_003_logo.jpg","cats":[6,20],"unis":[62],"id":476},"477":{"insts":[2644404],"language":"en","name":"How Green Is That Product? An Introduction to Environmental Life Cycle Assessment","short_name":"introtolca","order_idx":307,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/29/7f2aa812cc8b3fe20ddf1a7d4fd139/tree-logo-600x340.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/57/47b01348dd0747aae23180b3d6a8cf/tree-logo-600x340.jpg","cats":[15,16,25],"unis":[54],"id":477},"478":{"insts":[2660182],"language":"es","name":"Continuidad y desarrollo de la empresa familiar","short_name":"empresafamiliar","order_idx":308,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/d8/8054d6a2afce99d38bc283d93179e1/coursera_004_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/fb/98a0cd8a7881d5bce0157816adb84f/coursera_004_logo.jpg","cats":[2,13,20],"unis":[62],"id":478},"480":{"insts":[2673267,3543489],"language":"en","name":"Linear and Integer Programming","short_name":"linearprogramming","order_idx":309,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/36/fc3ac9d321e5e628016bfeb089e91d/lpLogo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/2e/414d8161b8ce374fc7c61d4853a9d6/lpLogo.png","cats":[1,15],"unis":[71],"id":480},"482":{"insts":[2674007],"language":"en","name":"Conditions of War and Peace","short_name":"warandpeace","order_idx":310,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/aa/5fe6a7ced4076a09e05e11490e041b/warandpeace_image.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/5b/e2cb4790128c5b69ac7b84f407f21d/warandpeace_image.jpg","cats":[20],"unis":[76],"id":482},"483":{"insts":[2673437],"language":"en","name":"From the Big Bang to Dark Energy","short_name":"bigbang","order_idx":311,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/86/dbd8db147e5031a005c3e0dcae59a9/Hubble_Ultra_Deep_Field_part_d_high.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/d4/192a92d619bfb50a16ad035f5f7f2d/Hubble_Ultra_Deep_Field_part_d_high.jpg","cats":[9,23],"unis":[76],"id":483},"484":{"insts":[2696515],"language":"en","name":"The Diversity of Exoplanets","short_name":"extrasolarplanets","order_idx":312,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/21/e3615ff6475b89079e4d83d026a1eb/exoplanet07.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/eb/8419ebf39f0f674254f4d23a54d5f2/exoplanet07.jpg","cats":[23],"unis":[49],"id":484},"485":{"insts":[2643309],"language":"en","name":"Fundamentals of Digital Image and Video Processing","short_name":"digital","order_idx":313,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/bf/d1a80b022b8abf215d1f977c071c2f/logo_aggelos.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6d/c49bbac1cbaecf9a2ff557e517634c/logo_aggelos.jpg","cats":[4,15,17],"unis":[54],"id":485},"486":{"insts":[2688952],"language":"en","name":"Introduction to Environmental Law and Policy","short_name":"environlaw","order_idx":314,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/67/269c534ed21a7ffd71a32a591a872c/dons-icon.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/0e/b19a9b92f14b52fb80de02a2aafe63/dons-icon.jpg","cats":[21],"unis":[77],"id":486},"487":{"insts":[2677973],"language":"en","name":"Physics 1 for Physical Science Majors","short_name":"physics1","order_idx":315,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/79/91c94b68cf01a3340b49b2516112ff/CourseraLogo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6d/f6613e9892e60add07be5d4876cf2d/CourseraLogo.jpg","cats":[23],"unis":[71],"id":487},"488":{"insts":[2685273,2685251,2685315,2685318,1841753,2685264,3307276,2685240,2685294,2685310,2685284],"language":"en","name":"Content Strategy for Professionals: Engaging Audiences for Your Organization","short_name":"contentstrategy","order_idx":316,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/a2/5eebe5eaecd87d6eb07304cbd9ef0f/Content-Strategy-logo2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/2e/b6ffdd5174cc93bb9b6dbe83b19879/Content-Strategy-logo2.jpg","cats":[4,13],"unis":[54],"id":488},"489":{"insts":[2679701],"language":"en","name":"Comic Books and Graphic Novels","short_name":"comics","order_idx":317,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c8/39a91068003dd6743aff935688f0a8/Comics-and-Graphic-Novels.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/d6/ba3d951f9beb0c015cc6fd9d453851/Comics-and-Graphic-Novels.png","cats":[6,22],"unis":[71],"id":489},"492":{"insts":[2658770],"language":"en","name":"Everything is the Same: Modeling Engineered Systems","short_name":"modelsystems","order_idx":318,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/50/2bb57d916637f0773343036f7639d0/TDMurpheyCourseraLogo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/90/130e81b0efc6b67dd2d3b6d2b0cd95/TDMurpheyCourseraLogo.jpg","cats":[15],"unis":[54],"id":492},"493":{"insts":[2675440],"language":"en","name":"Exploring Beethoven\u2019s Piano Sonatas","short_name":"beethovensonatas","order_idx":319,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c4/474f16f71c8b518170ff1db947ccaf/coursera-lvb.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/1a/3306f9e902fd6a5a87d3a98696b643/coursera-lvb.jpg","cats":[6,18],"unis":[79],"id":493},"494":{"insts":[2675437,2654261],"language":"en","name":"From the Repertoire: Western Music History through Performance","short_name":"musichistoryperforms","order_idx":320,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/3d/a668e537d3847c895fc257624190e6/Guido-2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/64/87fc4cb7eef570216c117145f46e79/Guido-2.jpg","cats":[6,18],"unis":[79],"id":494},"495":{"insts":[2694569],"language":"en","name":"Fundamentals of Rehearsing Music Ensembles","short_name":"music-ensembles","order_idx":321,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/b3/ac69eb858bbbc114edda6b6397d13b/music-logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f4/46af8ac9c104b8c7214412c4619f53/music-logo.jpg","cats":[18],"unis":[77],"id":495},"496":{"insts":[2690251],"language":"en","name":"Metadata: Organizing and Discovering Information","short_name":"metadata","order_idx":322,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/04/d1670669938ca4cb20c95828b0ba4b/meta1.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e4/d3deb5a22a1cbdef456382afcf18cf/meta1.jpg","cats":[4],"unis":[77],"id":496},"497":{"insts":[704621,2694658],"language":"en","name":"Epidemiology: The Basic Science of Public Health","short_name":"epidemiology","order_idx":323,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/4c/ca334e7b2d5c68de312a2a7eb91819/epid-mooc.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/91/eb6fa07bd62fd195025eded9cd998b/epid-mooc.jpg","cats":[8],"unis":[77],"id":497},"498":{"insts":[2688754,2688759,2688762],"language":"es","name":"Desarrollo r\u00e1pido de productos innovadores para mercados emergentes","short_name":"innovacion","order_idx":324,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/03/b25513bc9a3cde275d5fed817454a1/coursera_008_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/27/4fd27f6fa4c00ff5f56f3c114d2836/coursera_008_logo.jpg","cats":[2,13],"unis":[62],"id":498},"499":{"insts":[2295274],"language":"en","name":"Democratic Development","short_name":"democraticdev","order_idx":325,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/98/94645c11c97cf6da3a58bc75fc7fce/Icon_DualColor_Lg.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/3c/7cfe29a042bf613e495b7780d6b0fe/Icon_DualColor_Lg.png","cats":[6,20],"unis":[1],"id":499},"500":{"insts":[2683051],"language":"en","name":"Write Like Mozart: An Introduction to Classical Music Composition","short_name":"classicalcomp","order_idx":326,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/07/e6dd62eb34b47ac9831f8cad3e0074/coursera_icon-01.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/48/8be8515df990780962786c48259675/coursera_icon-01.png","cats":[18],"unis":[47],"id":500},"501":{"insts":[2683047],"language":"en","name":"Unpredictable? Randomness, Chance and Free Will","short_name":"randomness","order_idx":327,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c8/c0aecde616f776e58a9f6bc2d72205/RANDOMNESS.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/a1/53393d5b9ddd4a54962ae8a99d55fa/RANDOMNESS.jpg","cats":[16,23],"unis":[47],"id":501},"503":{"insts":[2672777],"language":"es","name":"Matem\u00e1ticas y movimiento","short_name":"precalculo","order_idx":328,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/98/cc0ec76869899685021844e16062f9/coursera_006_logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/1c/756d238ff1950d07b8c5203556345e/coursera_006_logo.jpg","cats":[5],"unis":[62],"id":503},"504":{"insts":[2690314,2690319],"language":"es","name":"Egiptolog\u00eda (Egyptology)","short_name":"egypt","order_idx":329,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/10/ebb0f9bd4ecb39769a1ddb714c49f2/Egiptologia.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/82/b052da328c5393fdcaade9b5f09b4d/Egiptologia.jpg","cats":[6],"unis":[80],"id":504},"505":{"insts":[2690311,118364,3189498],"language":"es","name":"Pre-Calculus","short_name":"precalc","order_idx":330,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f5/c3d1686ad339bac88817f6458f3002/precalculo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/a9/059f96ce31e9e8934d95e59c828a16/precalculo.png","cats":[5],"unis":[80],"id":505},"506":{"insts":[2690307],"language":"es","name":"Histolog\u00eda b\u00e1sica: los cuatro tejidos fundamentales ","short_name":"histologia","order_idx":331,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f3/0bcd476a45e63292f3aeff5552ba96/histologia_logo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/10/b599a9b167904fb7f8c306bb406150/histologia_logo.png","cats":[8,10],"unis":[80],"id":506},"508":{"insts":[2693792],"language":"de","name":"Einf\u00fchrung in Computer Vision","short_name":"compvision","order_idx":332,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/58/2d3041eb65a7d499fb670d86d0d934/Course_Logo_Computer_Vision.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/3f/cb4a7c3ce0e6ac6a504ed714fcf59f/Course_Logo_Computer_Vision.jpg","cats":[17],"unis":[78],"id":508},"509":{"insts":[2695162],"language":"en","name":"The Future of Humankind","short_name":"humankindfuture","order_idx":333,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7b/48fb8d834051e6baac0c6756c3773a/MC900071032.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/17/857704657c1e0c7721d860f550c7de/MC900071032.jpg","cats":[6],"unis":[67],"id":509},"512":{"insts":[2255684],"language":"en","name":"Introduction to Public Speaking","short_name":"publicspeak","order_idx":334,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/4d/361d70127232029166fdc007f578dc/Public-Speaking.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/08/78d611614345d3448aa02bee32e789/Public-Speaking.jpg","cats":[6,13,14,22],"unis":[15],"id":512},"524":{"insts":[3471976],"language":"en","name":"Globalization and You","short_name":"globalization","order_idx":335,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/43/3763723917a62729305ab23043ed7f/GlobalizationWordleBanner2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/50/945bed87d1f8745ec38aeb2090f644/GlobalizationWordleBanner2.jpg","cats":[2,6,20],"unis":[15],"id":524},"526":{"insts":[2075104,1164831,2083331,2083347],"language":"en","name":"Guinea Pigs, Heroes & Desperate Patients: The History & Ethics of Human Research","short_name":"humanresearch","order_idx":336,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/39/8c435446f27af68b1b7ad531e692ca/GuineaPigsHeroesPatients_Logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e3/b656f1c64eb69615dc1af6e6e0641d/GuineaPigsHeroesPatients_Logo.jpg","cats":[3,6,8,10,20],"unis":[8],"id":526},"527":{"insts":[2722532,3145522],"language":"en","name":"The Science of Safety in Healthcare","short_name":"healthcaresafety","order_idx":337,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/6d/bc038aff1da5c8c5c2294277118e76/healthcare_safety.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b7/d7601296287fba65cfe263bb54abc3/healthcare_safety.jpg","cats":[3,8],"unis":[8],"id":527},"537":{"insts":[3011727,2225883],"language":"en","name":"First-Year Composition 2.0","short_name":"gtcomp","order_idx":338,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/5b/34fea429e8a72bb6c4478b88b8a88a/LMC-icon5.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f3/ca7e818d789237fb52a3726f97ed04/LMC-icon5.png","cats":[6],"unis":[9],"id":537},"566":{"insts":[3408612,3693651],"language":"en","name":"Diabetes: Diagnosis, Treatment, and Opportunities","short_name":"ucsfdiabetes","order_idx":339,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/d3/043b263cc3da09fb0713ae8b4f7720/iStock_000011432889Small.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/89/e0f66467b37e22f10cbaffd1652d63/iStock_000011432889Small.jpg","cats":[3,8],"unis":[10],"id":566},"582":{"insts":[2705795],"language":"en","name":"Instructional Methods in Health Professions Education","short_name":"instructmethodshpe","order_idx":340,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f9/e0e9229696a4179e24c322d4d2534e/carens_Course_Logo_053113a.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/4b/a08f079c6db3497faef5438abde609/carens_Course_Logo_053113a.jpg","cats":[3,8,14],"unis":[3],"id":582},"584":{"insts":[3229025],"language":"en","name":"Practical tips to improve Asian American participation in cancer clinical trials","short_name":"clinicaltrials","order_idx":341,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/b3/068a613fce53c3de094abf25422474/cme.clinicaltrials.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/d5/1ed45f0db320a812c5e49bf292becf/cme.clinicaltrials.jpg","cats":[3],"unis":[1],"id":584},"591":{"insts":[3287070,3204080],"language":"en","name":"The Fall and Rise of Jerusalem","short_name":"jerusalem","order_idx":342,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/ca/833f4600de66e9d64737cd3cab4a4d/Courses.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/bc/922cc4fe440e85f02021af11dc8385/Courses.jpg","cats":[6],"unis":[110],"id":591},"592":{"insts":[3287177,3708694],"language":"en","name":"What a Plant Knows (and other things you didn\u2019t know about plants)","short_name":"plantknows","order_idx":343,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/d3/e2f2a24c37aa64a9e16ac38387301b/Courses2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ce/518719e523f99ab19de9e49e6a832a/Courses2.jpg","cats":[10],"unis":[110],"id":592},"594":{"insts":[3297297],"language":"en","name":"Genetics and Society: A Course for Educators","short_name":"amnhgenetics","order_idx":344,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f5/79afd5ae4c7ee37a7dc60bd9f65485/course_genetics.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/c1/a2948ad7001e855d2eb35f7c1d2827/course_genetics.jpg","cats":[8,10,14,26],"unis":[100],"id":594},"595":{"insts":[3300435],"language":"en","name":"Evolution: A Course for Educators","short_name":"amnhevolution","order_idx":345,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/6f/d4ff754f3530e0985bcca09a9c029e/course_evolution.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/60/02168b68a625e79e39db8433bdff14/course_evolution.jpg","cats":[10,14,26],"unis":[100],"id":595},"596":{"insts":[3297304,3298066],"language":"en","name":"The Dynamic Earth: A Course for Educators","short_name":"amnhearth","order_idx":346,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/71/2ca964b5ba3a061565b88e95d7ad39/earth_option1.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f4/1b12e45800bd0954e9efcb07cba332/earth_option1.jpg","cats":[9,14,26],"unis":[100],"id":596},"598":{"insts":[1466681],"language":"en","name":"Science, Technology, and Society in China II: History of S&T in Chinese Society","short_name":"stschina2","order_idx":347,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/d3/bedb174f3df59199e472323c1b753e/stschina2-course-logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b9/dba6086a4f56801c91e72b708230e5/stschina2-course-logo.jpg","cats":[20],"unis":[35],"id":598},"599":{"insts":[1466681],"language":"en","name":"Science, Technology, and Society in China III: The Present & Policy Implications","short_name":"stschina3","order_idx":348,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/20/973743f49f8c578b13708b3d38467b/stschina3-course-logo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/3e/111c8ebdef8aab24ef1c1aa685ede2/stschina3-course-logo.jpg","cats":[20],"unis":[35],"id":599},"600":{"insts":[3289416,3289263],"language":"en","name":"Student Thinking at the Core","short_name":"corethink","order_idx":349,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/a5/9e8dc25b6296434147e2ea73d16025/leverging-student-thinking.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b8/9431452cf8470b4b4767a7924b84e8/leverging-student-thinking.png","cats":[14,26],"unis":[37],"id":600},"607":{"insts":[3219339],"language":"en","name":"Art and Inquiry: Museum Teaching Strategies For Your Classroom ","short_name":"artinquiry","order_idx":350,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/66/a4444bbdf75ce9b19a1199b6bfd9b2/Coursera_240x135.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/dc/85bdee318e41f2bb4f99034a2e1587/Coursera_240x135.jpg","cats":[6,14,22,26],"unis":[107],"id":607},"613":{"insts":[3332104],"language":"en","name":"Teaching Character and Creating Positive Classrooms ","short_name":"teachingcharacter","order_idx":351,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f0/c09133e1cd65d9861ac15e97dcb977/54_Frank-01015216.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/73/5f37a47ea52014c85b0d97d516e17f/54_Frank-01015216.jpg","cats":[14,26],"unis":[104],"id":613},"614":{"insts":[3260920,3260925,3260930,3228961],"language":"en","name":"Tinkering Fundamentals: Integrating Making Activities into Your STEM Classroom","short_name":"tinkering","order_idx":352,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9b/4b317d2ba7c924654136e19139ad76/Tinkering_logo_with_dots_black_tm_RGB.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/38/558b86175666ce9002d79895f499bf/Tinkering_logo_with_dots_black_tm_RGB.png","cats":[9,14,26],"unis":[108],"id":614},"616":{"insts":[3332466,3164319,3343186,3343192],"language":"en","name":"Integrating Engineering Into Your Science Classroom","short_name":"teachengineering","order_idx":353,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/34/fe8df9aa2840176a343a541ebac8d0/TI-Builders.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/a3/cf20f6ca30287f4a1aa8c88aa9d678/TI-Builders.jpg","cats":[14,15,26],"unis":[108],"id":616},"620":{"insts":[2327335,3361949,3365638,3368459],"language":"en","name":"Effective Classroom Interactions: Supporting Young Children\u2019s Development","short_name":"earlychildhood","order_idx":354,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/66/600b8525621d0f8fdb4e59ef305baf/CourseLogo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6e/6a5fc6ea45cf14031527787c0e660f/CourseLogo.jpg","cats":[14,26],"unis":[18],"id":620},"621":{"insts":[1676603,3401945],"language":"en","name":"Emerging Trends & Technologies in the Virtual K-12 Classroom","short_name":"k12virtualtrends","order_idx":355,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/93/1a9178b88191db1e90d7defb67d675/Older-and-younger-fingers-on-Tablet.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/70/9ce4cc8692a33b7a7eb1920ddbbb85/Older-and-younger-fingers-on-Tablet.jpg","cats":[4,14,26],"unis":[30],"id":621},"622":{"insts":[3219450],"language":"en","name":"Surviving Your Rookie Year of Teaching: 3 Key Ideas & High Leverage Techniques","short_name":"rookieteaching","order_idx":356,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/67/1ca7631d2f36413226dffd996da015/Teacher-Brain_crop.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/a6/37f1223efbd5f11869ca976ca1acf9/Teacher-Brain_crop.png","cats":[14,26],"unis":[105],"id":622},"623":{"insts":[3360910,611232],"language":"en","name":"First Year Teaching (Elementary Grades) - Success from the Start","short_name":"start1styearteaching","order_idx":357,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/5e/8a981ca051fd07407ffe711e9f2357/success-from-start-3.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/0c/b0f70883762e0204cf4a6e4371906f/success-from-start-3.jpg","cats":[14,26],"unis":[103],"id":623},"624":{"insts":[3219450],"language":"en","name":"Coaching Teachers: Promoting Changes that Stick ","short_name":"coachingteachers","order_idx":358,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/76/97675033e93a4e6aa0110c31c8f1a8/coaching.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/79/40743767350110b045f4ee6aa99dd7/coaching.jpg","cats":[14,26],"unis":[105],"id":624},"631":{"insts":[3366373],"language":"en","name":"Foundations of Teaching for Learning 1: Introduction","short_name":"teach1","order_idx":359,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/38/5045d8c1ee6131ec3b4603cadbf948/CET-Updated-H264-720p1.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/01/082721c2f77eeae2d6909bb1e3e901/CET-Updated-H264-720p1.png","cats":[14,26],"unis":[106],"id":631},"632":{"insts":[3366383],"language":"en","name":"Foundations of Teaching for Learning 2: Being a Teacher","short_name":"teach2","order_idx":360,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/72/7d771c2d8a9af5d500c0081b55c4ab/CET-Updated-H264-720p2.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6b/1f73fe278d5d4d2f2beeec9eec8614/CET-Updated-H264-720p2.png","cats":[14,26],"unis":[106],"id":632},"633":{"insts":[3366390],"language":"en","name":"Foundations of Teaching for Learning 3: Learners and Learning","short_name":"teach3","order_idx":361,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/e3/9bb0e4cb941dbbf0b5cea4adbccced/CET-Updated-H264-720p3.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e4/cd4ec19c6827bc94cde9a14fa10ff3/CET-Updated-H264-720p3.png","cats":[14,26],"unis":[106],"id":633},"634":{"insts":[3366404],"language":"en","name":"Foundations of Teaching for Learning 4: Curriculum","short_name":"teach4","order_idx":362,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/c9/b2c4c29f93b87a224a194c55a08d35/CET-Updated-H264-720p4.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/0e/7d234155a80e1a5a76a7e7dcf64a2a/CET-Updated-H264-720p4.png","cats":[14,26],"unis":[106],"id":634},"635":{"insts":[3397716],"language":"en","name":"Structure Standing Still: The Statics of Everyday Objects","short_name":"staticsofobjects","order_idx":363,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/0a/71b67d86efdb976c1ede792955a003/Structure-Standing-Still.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ee/204629a81c72d42f8b84a73fd1c226/Structure-Standing-Still.jpg","cats":[15],"unis":[31],"id":635},"636":{"insts":[3219450],"language":"en","name":"On the Hunt for Feedback: Self-Directed Teacher Improvement","short_name":"teacherfeedback","order_idx":364,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/8e/74b450ba3151f79358ff8ad6290d05/feedback_bluered.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/03/891fd8a10083562450d8939eb3afa4/feedback_bluered.png","cats":[14,26],"unis":[105],"id":636},"637":{"insts":[3376806],"language":"en","name":"The Brain-Targeted Teaching\u00ae Model for 21st Century Schools","short_name":"braintargeted","order_idx":365,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/e1/57bbe4cf8922fbb5a256e4eb628de6/BTTmodel.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/21/5568251fb72559764d7f6f806dcac1/BTTmodel.png","cats":[14,26],"unis":[8],"id":637},"639":{"insts":[3360857],"language":"en","name":"Common Core in Action: Literacy Across Content Areas","short_name":"ccss-literacy1","order_idx":366,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/80/42fb869a201f7841c31a0fef9d1288/literacy.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/6e/76a0120e653506dbb90cec15419020/literacy.jpg","cats":[14,26],"unis":[103],"id":639},"640":{"insts":[3360852],"language":"en","name":"Common Core in Action: Math Formative Assessment","short_name":"ccss-math1","order_idx":367,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9a/4179c4a607601ef9e796db94ad80d6/mathteacher-student-whiteboard.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/bd/5fb8ed244974860205389315c4bbbc/mathteacher-student-whiteboard.jpg","cats":[5,14,26],"unis":[103],"id":640},"641":{"insts":[3227866],"language":"en","name":"Foundations of Teaching for Learning 5: Planning for Teaching and Learning","short_name":"teach5","order_idx":368,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/3a/bbc23f42de9d241e1b14d04f5c4875/CET-Updated-H264-720p5.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/48/d1de57407232e6c7eb8043a4c68d73/CET-Updated-H264-720p5.png","cats":[14,26],"unis":[106],"id":641},"642":{"insts":[3227866],"language":"en","name":"Foundations of Teaching for Learning 6: Introduction to Student Assessment","short_name":"teach6","order_idx":369,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/7a/0a3b56493fd899c98791c6f4ed10ec/CET-Updated-H264-720p6.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/a9/1caa5beef6ed117cc6a338469bc925/CET-Updated-H264-720p6.png","cats":[14,26],"unis":[106],"id":642},"643":{"insts":[3227866],"language":"en","name":"Foundations of Teaching for Learning 7: Being a Professional","short_name":"teach7","order_idx":370,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/aa/dbfc8a76513c16175b233561eca4e8/CET-Updated-H264-720p7.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/f8/197aaefefe50921ee413b2e480517d/CET-Updated-H264-720p7.png","cats":[14,26],"unis":[106],"id":643},"644":{"insts":[3227866],"language":"en","name":"Foundations of Teaching for Learning 8: Developing Relationships","short_name":"teach8","order_idx":371,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/a3/e2e3693c675e3568509c533badb338/CET-Updated-H264-720p8.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/4c/53c10e76b84001ce146287fe61d73d/CET-Updated-H264-720p8.png","cats":[14,26],"unis":[106],"id":644},"655":{"insts":[3395219],"language":"en","name":"Engaging Students through Cooperative Learning","short_name":"cooperativelearning","order_idx":372,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/a6/228fe8e8f4477258e1f38e0be9d603/DSC_6912.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/eb/df0bc9f5c358cb11dbcbbfa3394b12/DSC_6912.jpg","cats":[14,26],"unis":[8],"id":655},"669":{"insts":[3467705,3596990],"language":"en","name":"The Emergence of the Modern Middle East","short_name":"modernmiddleeast","order_idx":373,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/04/db41d119652a4790055fa53303a29c/Courses3.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/13/4cfd5ec3afa81337d12348f2c79c66/Courses3.jpg","cats":[6],"unis":[110],"id":669},"677":{"insts":[423879,599445],"language":"en","name":"Networks Illustrated: Principles without Calculus","short_name":"ni","order_idx":374,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/1d/48a762629d12419a7c75a5272693a5/ni-logo2.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/0b/221f5f08b7e39b1c5d5a2ea65fa239/ni-logo2.png","cats":[2,4,11],"unis":[4],"id":677},"678":{"insts":[3498945],"language":"en","name":"Roman Architecture","short_name":"romanarchitecture","order_idx":375,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/bf/6e901d4a18040693ebec348c841725/deek_courselogo.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/d8/96bb86b6f727c154bb07d83cf2674c/deek_courselogo.jpg","cats":[6,22],"unis":[109],"id":678},"679":{"insts":[3510175,565747,3510185,386687],"language":"en","name":"Inquiry Science Learning: Perspectives and Practices 1 - Science Leadership","short_name":"scileadership","order_idx":376,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/93/c8f57ea67affc265f72baebf4e45b4/courseraLogo1.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/45/ef62b46517da6fa6b8db0adb855655/courseraLogo1.png","cats":[14,26],"unis":[13],"id":679},"684":{"insts":[1513337],"language":"en","name":"Moralities of Everyday Life","short_name":"moralities","order_idx":377,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f5/34d1914360cd2ff2e756b121363854/shutterstock_45601228-sized.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/ee/efa58e71e9cb68079b66b54e08965f/shutterstock_45601228-sized.jpg","cats":[6,20],"unis":[109],"id":684},"685":{"insts":[3543921],"language":"en","name":"Financial Markets","short_name":"financialmarkets","order_idx":378,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/bc/2d7279280551371b4d855593fec29d/ECON252.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/9c/b9aa82b5f1b7c258da20398458d2e7/ECON252.jpg","cats":[2,13],"unis":[109],"id":685},"686":{"insts":[3544181],"language":"en","name":"Constitutional Law","short_name":"conlaw","order_idx":379,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/9f/fd496c103aac54416374f62e901a1b/ConLaw_Coursera_1200x680.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/e0/b203dbc0f0ad61320e026e7f1e73ac/ConLaw_Coursera_1200x680.jpg","cats":[20,21],"unis":[109],"id":686},"688":{"insts":[250165],"language":"en","name":"Analysis of Algorithms","short_name":"aofa","order_idx":380,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/45/e34eeed7950dbc63909ad29a7ffbce/aofa-logo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/dc/595ad15d7c62645b62e5f55852d47b/aofa-logo.png","cats":[1,5],"unis":[4],"id":688},"689":{"insts":[250165],"language":"en","name":"Analytic Combinatorics","short_name":"ac","order_idx":381,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/06/012812ead1a867cb838eef53a6f171/ac-logo.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/56/2605df3beb9ec5e5b2ae1f00e1e55d/ac-logo.png","cats":[1,5],"unis":[4],"id":689},"699":{"insts":[3360910,611232],"language":"en","name":"First Year Teaching (Secondary Grades) - Success from the Start","short_name":"1styearteachingms-hs","order_idx":382,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/33/9f07cb35428f62a048f5390754de9a/success-from-the-start-2.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/85/87ff00ec3eca2faa5ae1cf46d4d5ae/success-from-the-start-2.jpg","cats":[14,26],"unis":[103],"id":699},"703":{"insts":[3510175,565747,3510185,386687],"language":"en","name":"Inquiry Science Learning: Perspectives and Practices 2 - Techniques for Success","short_name":"inquirytechniques","order_idx":383,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/80/124f729735e5a34a7bdb1d78a695a4/courseraLogo2.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/2f/f77f8b19d31daa2dfba4b04e151112/courseraLogo2.png","cats":[14,26],"unis":[13],"id":703},"704":{"insts":[3510175,565747,3510185,386687],"language":"en","name":"Inquiry Science Learning: Perspectives and Practices 3 - Science Content Survey","short_name":"scicontentsurvey","order_idx":384,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/03/ddc7e886bf4b2d024bf42fc4490e79/courseraLogo3.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/72/d36c078edf6a0848369ef5257259af/courseraLogo3.png","cats":[14,26],"unis":[13],"id":704},"705":{"insts":[3510175,565747,3510185,386687],"language":"en","name":"Inquiry Science Learning: Perspectives & Practices 4 - Student-Centered Inquiry","short_name":"scistudentinquiry","order_idx":385,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/f2/30a62f5aa86e46b758cbc806d48ce2/courseraLogo4.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/09/fcc8276511c97249f13b7e5f531127/courseraLogo4.png","cats":[14,26],"unis":[13],"id":705},"706":{"insts":[3675391],"language":"en","name":"Using The Next Generation Science Standards for Students\u2019 Deeper Understanding ","short_name":"sciframework","order_idx":386,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/38/79fcd1e6df7955027deda75b02444a/courseraLogoFramework.png","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/b6/e0111148454133ce2dc2f156998313/courseraLogoFramework.png","cats":[14,26],"unis":[13],"id":706},"729":{"insts":[3491158],"language":"en","name":"Analysis of a Complex Kind","short_name":"complexanalysis","order_idx":387,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/6e/0740b9ba7219f054052d4b129837db/Slide1.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/a2/a156dfe552fa42b9a2732eeea5784d/Slide1.jpg","cats":[5],"unis":[34],"id":729},"755":{"insts":[2444381],"language":"en","name":"NANOTECHNOLOGY AND NANOSENSORS","short_name":"nanosensors","order_idx":388,"self_service_course_id":null,"small_icon_hover":"https://coursera-course-photos.s3.amazonaws.com/be/80424b58b61cb24f531cb256a5a5a3/sensor-1.jpg","has_full_data":false,"large_icon":"https://coursera-course-photos.s3.amazonaws.com/27/97d64d53bdfdad0a6dbbe715f4429f/sensor-1.jpg","cats":[10,15,24],"unis":[129],"id":755}},"cats":[{"id":1,"short_name":"cs-theory","name":"Computer Science: Theory"},{"id":2,"short_name":"economics","name":"Economics & Finance"},{"id":3,"short_name":"medicine","name":"Medicine"},{"id":4,"short_name":"infotech","name":"Information, Tech & Design"},{"id":5,"short_name":"math","name":"Mathematics"},{"id":6,"short_name":"humanities","name":"Humanities "},{"id":8,"short_name":"health","name":"Health & Society"},{"id":9,"short_name":"physical","name":"Physical & Earth Sciences"},{"id":10,"short_name":"biology","name":"Biology & Life Sciences"},{"id":11,"short_name":"cs-systems","name":"Computer Science: Systems & Security"},{"id":12,"short_name":"cs-programming","name":"Computer Science: Software Engineering"},{"id":13,"short_name":"business","name":"Business & Management"},{"id":14,"short_name":"education","name":"Education"},{"id":15,"short_name":"ee","name":"Engineering"},{"id":16,"short_name":"stats","name":"Statistics and Data Analysis"},{"id":17,"short_name":"cs-ai","name":"Computer Science: Artificial Intelligence"},{"id":18,"short_name":"music","name":"Music, Film, and Audio"},{"id":19,"short_name":"food","name":"Food and Nutrition"},{"id":20,"short_name":"socsci","name":"Social Sciences"},{"id":21,"short_name":"law","name":"Law"},{"id":22,"short_name":"arts","name":"Arts"},{"id":23,"short_name":"physics","name":"Physics"},{"id":24,"short_name":"chemistry","name":"Chemistry"},{"id":25,"short_name":"energy","name":"Energy & Earth Sciences"},{"id":26,"short_name":"teacherpd","name":"Teacher Professional Development"}],"insts":[{"first_name":"Daphne","last_name":"Koller","middle_name":"","short_name":null,"instructor_id":1257,"id":223},{"first_name":"Dan","last_name":"Boneh","middle_name":"","short_name":null,"instructor_id":774,"id":85},{"first_name":"Nick","last_name":"Parlante","middle_name":"","short_name":null,"instructor_id":1267,"id":217},{"first_name":"Alex","last_name":"Aiken","middle_name":"","short_name":null,"instructor_id":221514,"id":28},{"first_name":"Gautam","last_name":"Kaul","middle_name":"","short_name":null,"instructor_id":209008,"id":187},{"first_name":"Mohamed","last_name":"Noor","middle_name":"","short_name":null,"instructor_id":884310,"id":241},{"first_name":"Jennifer","last_name":"Campbell","middle_name":"","short_name":null,"instructor_id":681795,"id":61},{"first_name":"Paul","last_name":"Gries","middle_name":"","short_name":null,"instructor_id":682843,"id":260},{"first_name":"Geoffrey","last_name":"Hinton","middle_name":"","short_name":null,"instructor_id":831097,"id":154},{"first_name":"Don","last_name":"Johnson","middle_name":"H.","short_name":null,"instructor_id":557195,"id":102},{"first_name":"Keith","last_name":"Devlin","middle_name":"","short_name":null,"instructor_id":587683,"id":99},{"first_name":"Wen-mei","last_name":"Hwu","middle_name":"W.","short_name":"wen-meihwu","instructor_id":917653,"id":226},{"first_name":"Lawrence","last_name":"Angrave","middle_name":"","short_name":"lawrenceangrave","instructor_id":902954,"id":36},{"first_name":"Jos\u00e9","last_name":"V\u00e1zquez-Cognet","middle_name":"J.","short_name":"josevazquez-cognet","instructor_id":884324,"id":228},{"first_name":"Daniel","last_name":"McFarland","middle_name":"A.","short_name":null,"instructor_id":1139667,"id":14},{"first_name":"Jonathan","last_name":"Garb","middle_name":"","short_name":null,"instructor_id":1292607,"id":283},{"first_name":"Hank","last_name":"Lucas","middle_name":"C.","short_name":null,"instructor_id":1571429,"id":155},{"first_name":"Jim","last_name":"Fowler","middle_name":"","short_name":"jimfowler","instructor_id":1667833,"id":127},{"first_name":"Steve","last_name":"Everett","middle_name":"","short_name":"steveeverett","instructor_id":710240,"id":146},{"first_name":"David","last_name":"Wentzlaff ","middle_name":"","short_name":null,"instructor_id":419989,"id":212},{"first_name":"Mitchell","last_name":"Duneier","middle_name":"","short_name":null,"instructor_id":239857,"id":213},{"first_name":"Mung","last_name":"Chiang","middle_name":"","short_name":null,"instructor_id":423879,"id":69},{"first_name":"Jeff","last_name":"Ullman","middle_name":"","short_name":null,"instructor_id":1271,"id":215},{"first_name":"Dan","last_name":"Jurafsky","middle_name":"","short_name":null,"instructor_id":775,"id":221},{"first_name":"Christopher","last_name":"Manning","middle_name":"","short_name":null,"instructor_id":68850,"id":222},{"first_name":"Jeff","last_name":"Borland","middle_name":"","short_name":null,"instructor_id":1298506,"id":251},{"first_name":"Martin","last_name":"Odersky","middle_name":"","short_name":null,"instructor_id":672627,"id":275},{"first_name":"Charles","last_name":"Cockell","middle_name":"","short_name":null,"instructor_id":796896,"id":60},{"first_name":"Kristina","last_name":"Castel-Roberts","middle_name":"von","short_name":null,"instructor_id":2330496,"id":65},{"first_name":"Eric","last_name":"Zivot","middle_name":"","short_name":null,"instructor_id":1118525,"id":123},{"first_name":"Pedro","last_name":"Domingos","middle_name":"","short_name":null,"instructor_id":996548,"id":330},{"first_name":"John","last_name":"Hogenesch","middle_name":"","short_name":null,"instructor_id":471335,"id":156},{"first_name":"John ","last_name":"Murray","middle_name":"Isaac ","short_name":null,"instructor_id":1320449,"id":174},{"first_name":"Emma","last_name":"Meagher","middle_name":"Anne","short_name":null,"instructor_id":471278,"id":114},{"first_name":"Carol","last_name":"Muller","middle_name":"","short_name":null,"instructor_id":235007,"id":62},{"first_name":"Jonathan","last_name":"Moreno","middle_name":"D.","short_name":null,"instructor_id":435103,"id":350},{"first_name":"Paul","last_name":"Offit","middle_name":"A.","short_name":null,"instructor_id":654632,"id":353},{"first_name":"Elsa","last_name":"Brown","middle_name":"Barkley","short_name":null,"instructor_id":1474140,"id":108},{"first_name":"Catherine","last_name":"Lucey","middle_name":"R.","short_name":null,"instructor_id":883324,"id":66},{"first_name":"Michael","last_name":"Collins","middle_name":"","short_name":null,"instructor_id":1325520,"id":312},{"first_name":"Marilyn","last_name":"Lombardi","middle_name":"M.","short_name":null,"instructor_id":963741,"id":239},{"first_name":"Bob","last_name":"Barnes","middle_name":"","short_name":null,"instructor_id":972090,"id":55},{"first_name":"Vincent","last_name":"Lepetit","middle_name":"","short_name":"vincent","instructor_id":1074054,"id":390},{"first_name":"Jean-C\u00e9dric","last_name":"Chappelier","middle_name":"","short_name":"jcchappelier","instructor_id":1116355,"id":391},{"first_name":"Jamila","last_name":"Sam","middle_name":"","short_name":"jamilasam","instructor_id":1345762,"id":171},{"first_name":"Marco","last_name":"Picasso","middle_name":"","short_name":null,"instructor_id":1757953,"id":276},{"first_name":"Guillermo","last_name":"Sapiro","middle_name":"","short_name":null,"instructor_id":729871,"id":602},{"first_name":"Franklin","last_name":"Allen","middle_name":"","short_name":null,"instructor_id":2594168,"id":382},{"first_name":"George","last_name":"Hochmuth","middle_name":"J.","short_name":"hochmuth","instructor_id":1626852,"id":372},{"first_name":"Barbara","last_name":"Endicott-Popovsky","middle_name":"","short_name":null,"instructor_id":1506477,"id":115},{"first_name":"Roy","last_name":"Hamilton","middle_name":"","short_name":null,"instructor_id":2666366,"id":614},{"first_name":"Nathan","last_name":"Kutz","middle_name":"","short_name":null,"instructor_id":2666846,"id":618},{"first_name":"Antonio","last_name":"Rangel","middle_name":"","short_name":null,"instructor_id":459667,"id":287},{"first_name":"Friedrich","last_name":"Eisenbrand","middle_name":"","short_name":null,"instructor_id":1323227,"id":129},{"first_name":"Mark","last_name":"Hargreaves","middle_name":"","short_name":null,"instructor_id":1300189,"id":257},{"first_name":"Dave","last_name":"Ward","middle_name":"","short_name":null,"instructor_id":1604596,"id":90},{"first_name":"Duncan","last_name":"Pritchard","middle_name":"","short_name":null,"instructor_id":1935119,"id":296},{"first_name":"Michela","last_name":"Massimi","middle_name":"","short_name":null,"instructor_id":1935226,"id":298},{"first_name":"Suilin","last_name":"Lavelle","middle_name":"","short_name":null,"instructor_id":1935218,"id":295},{"first_name":"Matthew","last_name":"Chrisman","middle_name":"","short_name":null,"instructor_id":1935223,"id":297},{"first_name":"Allan","last_name":"Hazlett","middle_name":"","short_name":null,"instructor_id":1935212,"id":299},{"first_name":"Alasdair","last_name":"Richmond","middle_name":"","short_name":null,"instructor_id":1935209,"id":300},{"first_name":"Jennifer","last_name":"Clark","middle_name":"","short_name":"jclark","instructor_id":2102206,"id":320},{"first_name":"Zuzana","last_name":"Bic","middle_name":"","short_name":null,"instructor_id":1334447,"id":265},{"first_name":"Henry","last_name":"Lester","middle_name":"A.","short_name":null,"instructor_id":640696,"id":17},{"first_name":"Michael","last_name":"Kearns","middle_name":"","short_name":null,"instructor_id":555881,"id":349},{"first_name":"Michael","last_name":"Scharf","middle_name":"","short_name":"michaelscharf","instructor_id":2527015,"id":203},{"first_name":"Ira","last_name":"Pohl","middle_name":"","short_name":null,"instructor_id":2320972,"id":339},{"first_name":"Ou Fan Leo","last_name":"Lee","middle_name":"","short_name":"leeoufan","instructor_id":2589075,"id":362},{"first_name":"Wai","last_name":"Tsui","middle_name":"","short_name":"tsuiwai","instructor_id":2589701,"id":365},{"first_name":"Kit Tai","last_name":"Hau","middle_name":"","short_name":"kthau","instructor_id":981331,"id":358},{"first_name":"Hsien-yung Kenneth","last_name":"Pai","middle_name":"","short_name":"paihsienyung","instructor_id":2589497,"id":363},{"first_name":"Wei","last_name":"Hua","middle_name":"","short_name":"huawei","instructor_id":2589622,"id":364},{"first_name":"Ib","last_name":"Bondebjerg","middle_name":"","short_name":null,"instructor_id":2500042,"id":184},{"first_name":"Jens","last_name":"Holst","middle_name":"Juul","short_name":null,"instructor_id":2579174,"id":334},{"first_name":"Signe","last_name":"Torekov","middle_name":"S\u00f8rensen ","short_name":"torekov","instructor_id":2558013,"id":291},{"first_name":"Anders","last_name":"Holm","middle_name":"","short_name":null,"instructor_id":2566619,"id":308},{"first_name":"Arne","last_name":"Astrup","middle_name":"","short_name":null,"instructor_id":2569351,"id":309},{"first_name":"Bernardo","last_name":"Castellano","middle_name":"","short_name":"bcastellano","instructor_id":2690307,"id":684},{"first_name":"Peter","last_name":"Edwards","middle_name":"","short_name":null,"instructor_id":2683051,"id":653},{"first_name":"Robert","last_name":"Erickson","middle_name":"","short_name":"erickson","instructor_id":2659612,"id":628},{"first_name":"Paolo","last_name":"Matthiae","middle_name":"","short_name":"pmatthiae","instructor_id":2633312,"id":538},{"first_name":"Aggelos","last_name":"Katsaggelos","middle_name":"","short_name":null,"instructor_id":2643309,"id":566},{"first_name":"Esther","last_name":"Barron","middle_name":"","short_name":null,"instructor_id":2635797,"id":547},{"first_name":"Steve","last_name":"Reed","middle_name":"","short_name":null,"instructor_id":2642321,"id":565},{"first_name":"\u8449\u4e19\u6210 Ping-Cheng ","last_name":"Yeh (Benson)","middle_name":"","short_name":"benson","instructor_id":2602668,"id":527},{"first_name":"James","last_name":"Martin","middle_name":"","short_name":"jmartin","instructor_id":2695162,"id":696},{"first_name":"Gayle","last_name":"Allard","middle_name":"","short_name":"gayleallard","instructor_id":2595276,"id":383},{"first_name":"Dominic","last_name":"Massaro","middle_name":"William","short_name":null,"instructor_id":625560,"id":337},{"first_name":"Jo-Anne","last_name":"Murray","middle_name":"","short_name":null,"instructor_id":1604583,"id":11},{"first_name":"Margaret","last_name":"Root","middle_name":"V.","short_name":"peggyroot","instructor_id":2606384,"id":523},{"first_name":"Jeanne","last_name":"Liedtka","middle_name":"M.","short_name":"liedtka01","instructor_id":2506410,"id":205},{"first_name":"Scott","last_name":"Higgins","middle_name":"","short_name":null,"instructor_id":1291950,"id":236},{"first_name":"John","last_name":"Covach","middle_name":"","short_name":"johncovach","instructor_id":2599979,"id":506},{"first_name":"Flemming","last_name":"Konradsen","middle_name":"","short_name":null,"instructor_id":2566087,"id":306},{"first_name":"Fran\u00e7ois ","last_name":"Golse","middle_name":"","short_name":"francoisgolse","instructor_id":2580055,"id":335},{"first_name":"Yvan","last_name":"Martel","middle_name":"","short_name":"yvanmartel","instructor_id":2593202,"id":370},{"first_name":"\u5442\u4e16\u6d69 Shih-Hao","last_name":"Lu","middle_name":"","short_name":"lushihhao","instructor_id":2644105,"id":569},{"first_name":"Philip","last_name":"Zelikow","middle_name":"","short_name":null,"instructor_id":2135893,"id":249},{"first_name":"Kimberley","last_name":"Hagen","middle_name":"Sessions","short_name":"kbs.hagen","instructor_id":1319386,"id":210},{"first_name":"Paolo","last_name":"Prandoni","middle_name":"","short_name":null,"instructor_id":676340,"id":181},{"first_name":"Martin","last_name":"Vetterli","middle_name":"","short_name":null,"instructor_id":2141686,"id":182},{"first_name":"Michael","last_name":"Lenox","middle_name":"J.","short_name":null,"instructor_id":1400787,"id":246},{"first_name":"Jeffrey","last_name":"Moore","middle_name":"S. ","short_name":"jeffreymoore","instructor_id":903698,"id":178},{"first_name":"Michael","last_name":"Evans","middle_name":"","short_name":"michaelevans","instructor_id":907436,"id":122},{"first_name":"Jonathan","last_name":"Tomkin","middle_name":"","short_name":"jonathantomkin","instructor_id":901931,"id":227},{"first_name":"Wendell","last_name":"Porter","middle_name":"A.","short_name":"porter","instructor_id":2593281,"id":373},{"first_name":"Jon","last_name":"Barnett","middle_name":"","short_name":null,"instructor_id":2666862,"id":619},{"first_name":"John","last_name":"Freebairn","middle_name":"","short_name":null,"instructor_id":2666864,"id":620},{"first_name":"David","last_name":"Jamieson","middle_name":"","short_name":null,"instructor_id":2666866,"id":621},{"first_name":"Maurizio","last_name":"Toscano","middle_name":"","short_name":null,"instructor_id":1297886,"id":254},{"first_name":"Rachel","last_name":"Webster","middle_name":"","short_name":null,"instructor_id":1295661,"id":255},{"first_name":"Kristin","last_name":"Sainani","middle_name":"","short_name":null,"instructor_id":1367410,"id":225},{"first_name":"Michael","last_name":"Dennin","middle_name":"","short_name":null,"instructor_id":1321950,"id":266},{"first_name":"Nicholas","last_name":"Llewellyn","middle_name":"M.","short_name":"nicholasllewellyn","instructor_id":938149,"id":179},{"first_name":"Vicki","last_name":"Colvin","middle_name":"","short_name":null,"instructor_id":2280464,"id":79},{"first_name":"Daniel","last_name":"Mittleman","middle_name":"","short_name":null,"instructor_id":2666907,"id":625},{"first_name":"Henning","last_name":"Haack","middle_name":"","short_name":null,"instructor_id":2428255,"id":310},{"first_name":"Terry","last_name":"Matilsky","middle_name":"A.","short_name":null,"instructor_id":2650348,"id":586},{"first_name":"Stephen","last_name":"Marshak","middle_name":"","short_name":"stephenmarshak","instructor_id":901980,"id":229},{"first_name":"Michael","last_name":"Dubson","middle_name":"","short_name":"mdubson","instructor_id":2677973,"id":643},{"first_name":"Valerio","last_name":"Scarani","middle_name":"","short_name":"valerioscarani","instructor_id":2683047,"id":654},{"first_name":"Roger","last_name":"Barr","middle_name":"","short_name":null,"instructor_id":932645,"id":238},{"first_name":"Adam","last_name":"Frank","middle_name":"","short_name":"adamfrank","instructor_id":2340295,"id":562},{"first_name":"S.","last_name":"Djorgovski","middle_name":"George","short_name":null,"instructor_id":685941,"id":139},{"first_name":"Ronen","last_name":"Plesser","middle_name":"","short_name":null,"instructor_id":638605,"id":240},{"first_name":"Sian","last_name":"Bayne","middle_name":"","short_name":"sianbayne","instructor_id":950832,"id":200},{"first_name":"Jeremy","last_name":"Knox","middle_name":"","short_name":null,"instructor_id":306499,"id":165},{"first_name":"Hamish","last_name":"Macleod","middle_name":"A.","short_name":null,"instructor_id":1862154,"id":8},{"first_name":"Jen","last_name":"Ross","middle_name":"","short_name":null,"instructor_id":1292208,"id":201},{"first_name":"Christine ","last_name":"Sinclair","middle_name":"","short_name":null,"instructor_id":1301316,"id":73},{"first_name":"Adrienne","last_name":"Williams","middle_name":"","short_name":"awilliams","instructor_id":1324755,"id":25},{"first_name":"Diane","last_name":"O'Dowd","middle_name":"","short_name":null,"instructor_id":2598741,"id":386},{"first_name":"Matthew","last_name":"Jackson","middle_name":"O.","short_name":"jacksonm","instructor_id":1252,"id":166},{"first_name":"Pat","last_name":"Pattison","middle_name":"","short_name":null,"instructor_id":1340080,"id":326},{"first_name":"Dominique","last_name":"Rossin","middle_name":"","short_name":"dominiquerossin","instructor_id":2423001,"id":290},{"first_name":"Benjamin","last_name":"Werner","middle_name":"","short_name":"bwerner","instructor_id":1622801,"id":277},{"first_name":"Rob","last_name":"Rutenbar","middle_name":"A.","short_name":"robrutenbar","instructor_id":887472,"id":230},{"first_name":"Loudon","last_name":"Stearns","middle_name":"","short_name":null,"instructor_id":703888,"id":325},{"first_name":"David ","last_name":"Owens","middle_name":"A.","short_name":null,"instructor_id":1330818,"id":92},{"first_name":"John","last_name":"Hutchinson","middle_name":"Steven","short_name":null,"instructor_id":2666905,"id":624},{"first_name":"Carlo","last_name":"Cosmelli","middle_name":"","short_name":"ccosmelli","instructor_id":2633310,"id":539},{"first_name":"Yannis","last_name":"Tsividis","middle_name":"","short_name":null,"instructor_id":1292489,"id":190},{"first_name":"Dawn","last_name":"Song","middle_name":"","short_name":"dawnsong","instructor_id":95,"id":93},{"first_name":"John","last_name":"Mitchell","middle_name":"C","short_name":"jcmitchell","instructor_id":1039793,"id":719},{"first_name":"Mike","last_name":"Simon","middle_name":"","short_name":"mikesimon","instructor_id":2865239,"id":730},{"first_name":"St\u00e9phane","last_name":"Udry","middle_name":"","short_name":"udrys","instructor_id":2696515,"id":698},{"first_name":"Lisa","last_name":"Dierker","middle_name":"","short_name":null,"instructor_id":1121232,"id":233},{"first_name":"Raoul","last_name":"Mulder","middle_name":"","short_name":null,"instructor_id":979695,"id":252},{"first_name":"Mark","last_name":"Elgar","middle_name":"","short_name":null,"instructor_id":1343266,"id":253},{"first_name":"Gerhard","last_name":"Wickler","middle_name":"","short_name":"gwickler","instructor_id":585759,"id":131},{"first_name":"Austin","last_name":"Tate","middle_name":"","short_name":"austintate","instructor_id":895139,"id":20},{"first_name":"John","last_name":"Hawks","middle_name":"","short_name":"johnhawks","instructor_id":2605756,"id":516},{"first_name":"","last_name":"","middle_name":"","short_name":null,"instructor_id":2225883,"id":490},{"first_name":"Magnus","last_name":"Egerstedt","middle_name":"","short_name":"egerstedt","instructor_id":247285,"id":367},{"first_name":"Marcel","last_name":"Salath\u00e9","middle_name":"","short_name":"msalathe","instructor_id":72633,"id":556},{"first_name":"Ottar","last_name":"Bjornstad","middle_name":"N.","short_name":"objornstad","instructor_id":2687735,"id":666},{"first_name":"Andrew","last_name":"Read","middle_name":"","short_name":"areed","instructor_id":2687745,"id":667},{"first_name":"Rachel","last_name":"Smith","middle_name":"A.","short_name":"rsmith","instructor_id":2687752,"id":669},{"first_name":"Mary","last_name":"Poss","middle_name":"L.","short_name":"mposs","instructor_id":2687763,"id":670},{"first_name":"David","last_name":"Hughes","middle_name":"P.","short_name":"dhughes","instructor_id":2687771,"id":671},{"first_name":"Peter","last_name":"Hudson","middle_name":"","short_name":"phudson","instructor_id":2687778,"id":672},{"first_name":"Matthew","last_name":"Ferrari","middle_name":"","short_name":"mferrari","instructor_id":2687782,"id":673},{"first_name":"Kevin","last_name":"Wayne","middle_name":"","short_name":null,"instructor_id":246867,"id":204},{"first_name":"Robert","last_name":"Sedgewick","middle_name":"","short_name":null,"instructor_id":250165,"id":211},{"first_name":"Charles","last_name":"Clark","middle_name":"W.","short_name":null,"instructor_id":324786,"id":68},{"first_name":"Victor","last_name":"Galitski","middle_name":"","short_name":null,"instructor_id":724736,"id":272},{"first_name":"Mark","last_name":"Braunstein","middle_name":"L.","short_name":"braunstein","instructor_id":2306102,"id":371},{"first_name":"Tom ","last_name":"Morley","middle_name":"","short_name":"morley","instructor_id":2468250,"id":375},{"first_name":"Tucker","last_name":"Balch","middle_name":"","short_name":"balch","instructor_id":861614,"id":286},{"first_name":"Wayne","last_name":"Whiteman","middle_name":"","short_name":"whiteman","instructor_id":1900891,"id":374},{"first_name":"Sarah","last_name":"Eichhorn","middle_name":"","short_name":null,"instructor_id":1350643,"id":262},{"first_name":"Rachel","last_name":"Lehman","middle_name":"Cohen","short_name":null,"instructor_id":1499033,"id":263},{"first_name":"Brian","last_name":"Bushee","middle_name":"J","short_name":null,"instructor_id":1937011,"id":58},{"first_name":"Raymond W.","last_name":"Yeung","middle_name":"","short_name":"raymondyeung","instructor_id":2600275,"id":497},{"first_name":"Alison","last_name":"Gibbs","middle_name":"","short_name":"alisongibbs","instructor_id":1084582,"id":31},{"first_name":"Jeffrey","last_name":"Rosenthal","middle_name":"","short_name":null,"instructor_id":2068199,"id":261},{"first_name":"Raymond","last_name":"Leger","middle_name":"J. St.","short_name":null,"instructor_id":1820338,"id":273},{"first_name":"Tammatha","last_name":"O'Brien","middle_name":"","short_name":null,"instructor_id":1820329,"id":274},{"first_name":"Richard","last_name":"Adelstein","middle_name":"","short_name":null,"instructor_id":1321389,"id":234},{"first_name":"Arturo","last_name":"Molina Guti\u00e9rrez ","middle_name":"","short_name":"arturomolina","instructor_id":2688754,"id":675},{"first_name":"David ","last_name":"Romero D\u00edaz","middle_name":"","short_name":"davidromero","instructor_id":2688759,"id":676},{"first_name":"Pedro","last_name":"Ponce Cruz","middle_name":"","short_name":"pedroponce","instructor_id":2688762,"id":677},{"first_name":"Denise","last_name":"Comer","middle_name":"","short_name":null,"instructor_id":1462466,"id":80},{"first_name":"Constance","last_name":"Steinkuehler","middle_name":"","short_name":"steinkuehler","instructor_id":2605719,"id":512},{"first_name":"Kurt","last_name":"Squire","middle_name":"","short_name":"kurtsquire","instructor_id":2605744,"id":513},{"first_name":"Patricia","last_name":"Salinas Mart\u00ednez","middle_name":"","short_name":"patysalinas","instructor_id":2672777,"id":685},{"first_name":"Richard","last_name":"Alley","middle_name":"B.","short_name":"richard","instructor_id":2645422,"id":587},{"first_name":"Douglas","last_name":"Schmidt","middle_name":"C.","short_name":null,"instructor_id":1337829,"id":84},{"first_name":"Ezekiel","last_name":"Emanuel","middle_name":"J.","short_name":null,"instructor_id":1806984,"id":525},{"first_name":"Gautam","last_name":"Shroff","middle_name":"","short_name":null,"instructor_id":107347,"id":137},{"first_name":"Edward","last_name":"Hess","middle_name":"D.","short_name":null,"instructor_id":988020,"id":10},{"first_name":"Jean-Paul","last_name":"Restoule","middle_name":"","short_name":null,"instructor_id":874189,"id":259},{"first_name":"Anthony","last_name":"Rostain","middle_name":"L.","short_name":null,"instructor_id":2666378,"id":615},{"first_name":"","last_name":"","middle_name":"","short_name":null,"instructor_id":2996815,"id":767},{"first_name":"Nilss","last_name":"Olekalns","middle_name":"","short_name":null,"instructor_id":937126,"id":258},{"first_name":"Avi","last_name":"Ma\u2019ayan","middle_name":"","short_name":"avimaayan","instructor_id":1305172,"id":41},{"first_name":"Eric","last_name":"Sobie","middle_name":"","short_name":null,"instructor_id":1325618,"id":116},{"first_name":"Leonard","last_name":"White","middle_name":"E.","short_name":null,"instructor_id":901314,"id":242},{"first_name":"Sam","last_name":"Shelton","middle_name":"","short_name":"shelton","instructor_id":862822,"id":368},{"first_name":"Michael","last_name":"Genesereth","middle_name":"","short_name":null,"instructor_id":1460,"id":138},{"first_name":"Daniel","last_name":"Ogilvie","middle_name":"M.","short_name":"ogilvie","instructor_id":2645301,"id":573},{"first_name":"Leonard","last_name":"Hamilton","middle_name":"W.","short_name":"soulbeliefs","instructor_id":2645318,"id":574},{"first_name":"Murray","last_name":"Baumgarten","middle_name":"","short_name":null,"instructor_id":2589160,"id":499},{"first_name":"Peter","last_name":"Kenez","middle_name":"","short_name":null,"instructor_id":2588904,"id":498},{"first_name":"Francesco ","last_name":"Fiore","middle_name":"Paolo","short_name":"f.p.fiore","instructor_id":2633305,"id":540},{"first_name":"Fernando ","last_name":"Sandoval Arzaga","middle_name":"","short_name":"fsandoval","instructor_id":2660182,"id":608},{"first_name":"Kiichi","last_name":"Fujiwara","middle_name":"","short_name":"kiichifujiwara","instructor_id":2674007,"id":634},{"first_name":"Kris","last_name":"Olds","middle_name":"","short_name":"krisolds","instructor_id":2605731,"id":517},{"first_name":"Susan","last_name":"Robertson","middle_name":"L.","short_name":"susanrobertson","instructor_id":2687823,"id":668},{"first_name":"Idan","last_name":"Segev","middle_name":"","short_name":null,"instructor_id":1213805,"id":160},{"first_name":"Ajay","last_name":"Kapur","middle_name":"","short_name":"ajaykapur","instructor_id":2660238,"id":609},{"first_name":"Gilbert","last_name":"Probst","middle_name":"","short_name":"probst","instructor_id":2683483,"id":655},{"first_name":"Larry","last_name":"Lagerstrom","middle_name":"Randles","short_name":"larrylagerstrom","instructor_id":2691794,"id":692},{"first_name":"Dan ","last_name":"Grossman","middle_name":"","short_name":null,"instructor_id":873260,"id":104},{"first_name":"Gaetano","last_name":"Borriello","middle_name":"","short_name":null,"instructor_id":2602091,"id":508},{"first_name":"Luis","last_name":"Ceze","middle_name":"","short_name":null,"instructor_id":1562358,"id":387},{"first_name":"Larry","last_name":"Diamond","middle_name":"","short_name":null,"instructor_id":2295274,"id":717},{"first_name":"Karin","last_name":"Yeatts","middle_name":"","short_name":null,"instructor_id":704621,"id":686},{"first_name":"Lorraine","last_name":"Alexander","middle_name":"","short_name":null,"instructor_id":2694658,"id":695},{"first_name":"Eric","last_name":"Masanet","middle_name":"","short_name":"ericmasanet","instructor_id":2644404,"id":570},{"first_name":"Andrew","last_name":"Szegedy-Maszak","middle_name":"","short_name":null,"instructor_id":802670,"id":40},{"first_name":"Walter","last_name":" Sinnott-Armstrong","middle_name":"","short_name":null,"instructor_id":932346,"id":244},{"first_name":"Ram ","last_name":"Neta","middle_name":"","short_name":null,"instructor_id":935146,"id":107},{"first_name":"Robert ","last_name":"Clark","middle_name":"","short_name":"robclark","instructor_id":2359335,"id":379},{"first_name":"Mark ","last_name":"Bocko","middle_name":"","short_name":"markbocko","instructor_id":2204104,"id":380},{"first_name":"Randall","last_name":"Wright","middle_name":"","short_name":"randallwright","instructor_id":2605772,"id":515},{"first_name":"Guadalupe","last_name":"Vadillo","middle_name":"","short_name":"guadalupe","instructor_id":323100,"id":207},{"first_name":"Irfan","last_name":"Essa","middle_name":"","short_name":"irfanessa","instructor_id":868530,"id":500},{"first_name":"Anderson ","last_name":"Smith","middle_name":"D.","short_name":"smith","instructor_id":2606554,"id":522},{"first_name":"Fatimah","last_name":"Wirth","middle_name":"","short_name":"wirth","instructor_id":861494,"id":124},{"first_name":"Williams","last_name":"Ettouati","middle_name":"S.","short_name":"ettouati","instructor_id":289468,"id":173},{"first_name":"Joseph","last_name":"Ma","middle_name":"D.","short_name":null,"instructor_id":2480111,"id":177},{"first_name":"Kevin","last_name":"Korsyn","middle_name":"","short_name":"kevinkorsyn","instructor_id":640270,"id":270},{"first_name":"Michael ","last_name":"Oakes","middle_name":"","short_name":"michaeloakes","instructor_id":2605293,"id":514},{"first_name":"Gregor","last_name":"Kiczales","middle_name":"","short_name":null,"instructor_id":359948,"id":143},{"first_name":"Jeffrey","last_name":"Kahn","middle_name":"","short_name":null,"instructor_id":2075104,"id":185},{"first_name":"Alan","last_name":"Regenberg","middle_name":"C","short_name":"regenberg","instructor_id":1164831,"id":30},{"first_name":"Debra","last_name":"Mathews","middle_name":"JH","short_name":"debramathews","instructor_id":2083331,"id":106},{"first_name":"Joseph","last_name":"Ali","middle_name":"","short_name":"josephali","instructor_id":2083347,"id":167},{"first_name":"Rajesh","last_name":"Rao","middle_name":"P. N.","short_name":null,"instructor_id":1522272,"id":388},{"first_name":"Adrienne","last_name":"Fairhall","middle_name":"","short_name":null,"instructor_id":1282559,"id":389},{"first_name":"Orin","last_name":"Starn","middle_name":"","short_name":null,"instructor_id":1159084,"id":519},{"first_name":"William","last_name":"Kuskin","middle_name":"","short_name":"kuskin","instructor_id":2679701,"id":648},{"first_name":"Yaakov","last_name":"Nahmias","middle_name":"","short_name":"ynahmias","instructor_id":1297453,"id":282},{"first_name":"Jennifer","last_name":"Evans-Cowley","middle_name":"","short_name":"evanscowley","instructor_id":1843870,"id":81},{"first_name":"Thomas ","last_name":"Sanchez","middle_name":"W.","short_name":null,"instructor_id":1847439,"id":319},{"first_name":"Jennifer","last_name":"Widom","middle_name":"","short_name":null,"instructor_id":1196954,"id":220},{"first_name":"James","last_name":"Lee","middle_name":"Z.","short_name":null,"instructor_id":1465513,"id":280},{"first_name":"Byung-Ho ","last_name":"Lee","middle_name":"","short_name":null,"instructor_id":1311294,"id":902},{"first_name":"Carlos","last_name":"Gershenson","middle_name":"","short_name":"carlos","instructor_id":2533383,"id":208},{"first_name":"Maya","last_name":"Adam","middle_name":"","short_name":"madam","instructor_id":2395490,"id":188},{"first_name":"Scott ","last_name":"Klemmer","middle_name":"","short_name":null,"instructor_id":1250,"id":175},{"first_name":"Jon","last_name":"Stewart","middle_name":"","short_name":null,"instructor_id":2619522,"id":541},{"first_name":"Naubahar","last_name":"Sharif","middle_name":"","short_name":null,"instructor_id":1466681,"id":281},{"first_name":"Andrew","last_name":"Conway","middle_name":"","short_name":"andrewconway","instructor_id":419984,"id":5},{"first_name":"Karl ","last_name":"Ulrich","middle_name":"T.","short_name":"ulrich","instructor_id":341966,"id":346},{"first_name":"Christian","last_name":"Terwiesch","middle_name":"","short_name":null,"instructor_id":1349478,"id":345},{"first_name":"Bill","last_name":"Howe","middle_name":"","short_name":null,"instructor_id":999946,"id":51},{"first_name":"Randall","last_name":"LeVeque ","middle_name":"J.","short_name":"leveque","instructor_id":1320364,"id":729},{"first_name":"Mariale ","last_name":"Hardiman","middle_name":"","short_name":"mmhardiman","instructor_id":3376806,"id":920},{"first_name":"Barbara","last_name":"Stengel","middle_name":"S.","short_name":"barbs","instructor_id":3289416,"id":863},{"first_name":"Marcy","last_name":"Singer-Gabella","middle_name":"","short_name":"marcysg","instructor_id":3289263,"id":862},{"first_name":"Dave","last_name":"Levin","middle_name":"","short_name":"davelevin","instructor_id":3332104,"id":885},{"first_name":"Orin ","last_name":"Gutlerner","middle_name":"","short_name":"oringut","instructor_id":3219450,"id":906},{"first_name":"John","last_name":"MacBeath","middle_name":"","short_name":"johnmacbeath","instructor_id":3366373,"id":912},{"first_name":"Dennis","last_name":"Francis","middle_name":"","short_name":"dennisfrancis","instructor_id":3366383,"id":913},{"first_name":"George","last_name":"Oduro","middle_name":"","short_name":"georgeoduro","instructor_id":3366390,"id":914},{"first_name":"Suseela","last_name":"Malakolunthu","middle_name":"","short_name":"suseelamalakolunthu","instructor_id":3366404,"id":915},{"first_name":"Kevin","last_name":"Drinkard","middle_name":"","short_name":"kevindrinkard","instructor_id":3360852,"id":909},{"first_name":"Lisa","last_name":"Mount","middle_name":"","short_name":"lisamount","instructor_id":3360857,"id":908},{"first_name":"Linda","last_name":"Shore","middle_name":" ","short_name":"lindashore","instructor_id":3332466,"id":897},{"first_name":"Eric","last_name":"Muller","middle_name":"","short_name":"ericmuller","instructor_id":3164319,"id":898},{"first_name":"Julie","last_name":"Yu","middle_name":"","short_name":"julieyu","instructor_id":3343186,"id":899},{"first_name":"Paul","last_name":"Doherty","middle_name":"","short_name":"pauldoherty","instructor_id":3343192,"id":900},{"first_name":"Peter","last_name":"Struck","middle_name":"","short_name":null,"instructor_id":422471,"id":348},{"first_name":"Jennifer ","last_name":"Sherer","middle_name":"Zoltners","short_name":null,"instructor_id":1280592,"id":232},{"first_name":"Lauren","last_name":"Resnick","middle_name":"","short_name":null,"instructor_id":2606081,"id":528},{"first_name":"Juan","last_name":"Donaire","middle_name":"Jes\u00fas","short_name":"jjdonaire","instructor_id":2690311,"id":683},{"first_name":"Jaume","last_name":"Pujol","middle_name":"","short_name":"jpujol","instructor_id":118364,"id":826},{"first_name":"Merc\u00e8","last_name":"Villanueva","middle_name":"","short_name":"mvillanueva","instructor_id":3189498,"id":830},{"first_name":"Josep","last_name":"Cervell\u00f3","middle_name":"","short_name":"jcervello","instructor_id":2690314,"id":682},{"first_name":"Jose","last_name":"Lull","middle_name":"","short_name":"jlull","instructor_id":2690319,"id":681},{"first_name":"Commonwealth Education Trust instructor","last_name":"","middle_name":"","short_name":"cet1886","instructor_id":3227866,"id":930},{"first_name":"Steve","last_name":"Joordens","middle_name":"","short_name":null,"instructor_id":1915980,"id":477},{"first_name":"Kevin","last_name":"Leyton-Brown","middle_name":"","short_name":null,"instructor_id":174814,"id":219},{"first_name":"Yoav","last_name":"Shoham","middle_name":"","short_name":null,"instructor_id":1251,"id":218},{"first_name":"Fei-Fei","last_name":"Li","middle_name":"","short_name":null,"instructor_id":2666324,"id":611},{"first_name":"Silvio","last_name":"Savarese","middle_name":"","short_name":null,"instructor_id":2666329,"id":612},{"first_name":"Jamie ","last_name":"Pope","middle_name":"","short_name":null,"instructor_id":1331704,"id":168},{"first_name":"Mike","last_name":"Petrich","middle_name":"","short_name":"mikep","instructor_id":3260920,"id":894},{"first_name":"Karen","last_name":"Wilkinson","middle_name":"","short_name":"karenw","instructor_id":3260925,"id":893},{"first_name":"Luigi","last_name":"Anzivino","middle_name":"","short_name":"luigia","instructor_id":3260930,"id":895},{"first_name":"Bronwyn","last_name":"Bevan","middle_name":"","short_name":"bronwynb","instructor_id":3228961,"id":896},{"first_name":"Simon ","last_name":"Green","middle_name":"","short_name":null,"instructor_id":2603322,"id":503},{"first_name":"Bridget","last_name":"Hamre","middle_name":"K.","short_name":null,"instructor_id":2327335,"id":919},{"first_name":"Grace","last_name":"Funk","middle_name":"W.","short_name":null,"instructor_id":3361949,"id":918},{"first_name":"Allison","last_name":"Leach","middle_name":"P.","short_name":null,"instructor_id":3365638,"id":917},{"first_name":"Kathy","last_name":"Neesen","middle_name":"","short_name":null,"instructor_id":3368459,"id":916},{"first_name":"Paul","last_name":"Miller","middle_name":"D.","short_name":"pmiller","instructor_id":3395219,"id":923},{"first_name":"Rosemary","last_name":"Redfield","middle_name":"","short_name":null,"instructor_id":543459,"id":323},{"first_name":"Andrew","last_name":"Ng","middle_name":"","short_name":null,"instructor_id":1244,"id":35},{"first_name":"Donald","last_name":"Dingwell","middle_name":"Bruce","short_name":null,"instructor_id":2602095,"id":501},{"first_name":"Thaddeus","last_name":"Hogarth","middle_name":"","short_name":null,"instructor_id":1338222,"id":324},{"first_name":"Ravi","last_name":"Iyengar","middle_name":"","short_name":"raviiyengar","instructor_id":1325616,"id":250},{"first_name":"Anna","last_name":"Divinsky","middle_name":"","short_name":"adivinsky","instructor_id":2650854,"id":588},{"first_name":"Susan","last_name":"Delagrange","middle_name":"","short_name":"susandelagrange","instructor_id":1505164,"id":98},{"first_name":"Scott ","last_name":"DeWitt","middle_name":"Lloyd ","short_name":"scottdewitt","instructor_id":2041603,"id":100},{"first_name":"Kay","last_name":"Halasek","middle_name":"","short_name":"kayhalasek","instructor_id":1957524,"id":148},{"first_name":"Ben","last_name":"McCorkle","middle_name":"","short_name":"benmccorkle","instructor_id":2029839,"id":482},{"first_name":"Cynthia","last_name":"Selfe","middle_name":"","short_name":"cynthiaselfe","instructor_id":1893981,"id":476},{"first_name":"R.","last_name":"Freeman","middle_name":"Edward","short_name":"edfreeman","instructor_id":2700511,"id":701},{"first_name":"Michael","last_name":"Schatz","middle_name":"F.","short_name":"schatz","instructor_id":2982963,"id":760},{"first_name":"Sriram","last_name":"Sankaranarayanan","middle_name":"","short_name":"sriram","instructor_id":2673267,"id":629},{"first_name":"Shalom","last_name":"Ruben","middle_name":"D.","short_name":"shalom","instructor_id":3543489,"id":970},{"first_name":"Bob","last_name":"Shiller","middle_name":"","short_name":"bobshiller","instructor_id":3543921,"id":966},{"first_name":"Diana","last_name":"Kleiner","middle_name":"E.E.","short_name":"dianaeekleiner","instructor_id":3498945,"id":950},{"first_name":"Dan","last_name":"Ariely","middle_name":"","short_name":"danariely","instructor_id":680709,"id":88},{"first_name":"Martin","last_name":"Haugh","middle_name":"","short_name":null,"instructor_id":1325435,"id":354},{"first_name":"Garud","last_name":"Iyengar","middle_name":"","short_name":null,"instructor_id":1325459,"id":133},{"first_name":"Karen ","last_name":"Monsen","middle_name":"","short_name":"karenmonsen","instructor_id":2608269,"id":524},{"first_name":"Gary","last_name":"Burton","middle_name":"","short_name":null,"instructor_id":1338423,"id":134},{"first_name":"Jeremy","last_name":"Adelman","middle_name":"","short_name":null,"instructor_id":419843,"id":23},{"first_name":"Sarah","last_name":"Burch","middle_name":"","short_name":null,"instructor_id":1342536,"id":321},{"first_name":"Sara","last_name":"Harris","middle_name":"","short_name":null,"instructor_id":1989083,"id":322},{"first_name":"Christopher","last_name":"Cramer","middle_name":"J. ","short_name":"chriscramer","instructor_id":2601001,"id":510},{"first_name":"Jay","last_name":"Clayton","middle_name":"","short_name":null,"instructor_id":272543,"id":172},{"first_name":"Kevin","last_name":"Werbach","middle_name":"","short_name":null,"instructor_id":226710,"id":347},{"first_name":"Lawrence (Larry)","last_name":"Barkley","middle_name":"","short_name":"larrybarkley","instructor_id":2653254,"id":592},{"first_name":"Ted","last_name":"Blake","middle_name":"","short_name":"tedblake","instructor_id":2653304,"id":593},{"first_name":"Lorrie","last_name":"Ross","middle_name":"","short_name":"lorrieross","instructor_id":2191978,"id":945},{"first_name":"Robert","last_name":"Ghrist","middle_name":"","short_name":null,"instructor_id":227062,"id":140},{"first_name":"Rebecca","last_name":"Stein","middle_name":"","short_name":null,"instructor_id":248242,"id":351},{"first_name":"Joel","last_name":"Cracraft","middle_name":"","short_name":"cracraft","instructor_id":3300435,"id":874},{"first_name":"Rob","last_name":"DeSalle","middle_name":"","short_name":"desalle","instructor_id":3297297,"id":868},{"first_name":"Emmett","last_name":"Sullivan","middle_name":"","short_name":null,"instructor_id":2625760,"id":530},{"first_name":"Edmond","last_name":"Mathez","middle_name":"","short_name":"mathez","instructor_id":3297304,"id":867},{"first_name":"Ro","last_name":"Kinzler","middle_name":"","short_name":"kinzler","instructor_id":3298066,"id":871},{"first_name":"Benjamin","last_name":"Abella","middle_name":"","short_name":null,"instructor_id":2666347,"id":613},{"first_name":"","last_name":"","middle_name":"","short_name":null,"instructor_id":237513,"id":983},{"first_name":"Polly","last_name":"Price","middle_name":"J.","short_name":"pollyprice","instructor_id":1324701,"id":209},{"first_name":"Joseph","last_name":"Yam","middle_name":"","short_name":"josephyam","instructor_id":2600270,"id":496},{"first_name":"Terence Tai-Leung","last_name":"Chong","middle_name":"","short_name":"terencechong","instructor_id":2600267,"id":495},{"first_name":"Nick","last_name":"Feamster","middle_name":"","short_name":"feamster","instructor_id":1743955,"id":376},{"first_name":"Keeve","last_name":"Nachman","middle_name":"","short_name":null,"instructor_id":687518,"id":313},{"first_name":"Robert","last_name":"Lawrence","middle_name":"S.","short_name":null,"instructor_id":2286634,"id":509},{"first_name":"Scott","last_name":"Zeger","middle_name":"L.","short_name":"scottzeger","instructor_id":2276941,"id":518},{"first_name":"William","last_name":"Brieger","middle_name":"","short_name":null,"instructor_id":660062,"id":46},{"first_name":"Roger","last_name":"Peng","middle_name":"","short_name":null,"instructor_id":685384,"id":314},{"first_name":"Jeff","last_name":"Leek","middle_name":"","short_name":null,"instructor_id":694443,"id":315},{"first_name":"Henry","last_name":"Perry","middle_name":"","short_name":null,"instructor_id":693038,"id":152},{"first_name":"Brian","last_name":"Caffo","middle_name":"","short_name":null,"instructor_id":688901,"id":47},{"first_name":"Kevin","last_name":"Frick","middle_name":"","short_name":null,"instructor_id":681157,"id":316},{"first_name":"Marco","last_name":"Gillies","middle_name":"","short_name":"marcogillies","instructor_id":1620951,"id":195},{"first_name":"Matthew","last_name":"Yee-King","middle_name":"","short_name":null,"instructor_id":1960981,"id":196},{"first_name":"Mick","last_name":"Grierson","middle_name":"","short_name":null,"instructor_id":1961937,"id":197},{"first_name":"Akhil","last_name":"Amar","middle_name":"Reed","short_name":"akhilamar","instructor_id":3544181,"id":967},{"first_name":"Arnold","last_name":"Weinstein","middle_name":"","short_name":null,"instructor_id":1314970,"id":6},{"first_name":"Bobby","last_name":"Calder","middle_name":"","short_name":"bobbycalder","instructor_id":2685273,"id":658},{"first_name":"Candy","last_name":"Lee","middle_name":"","short_name":"candylee","instructor_id":2685251,"id":656},{"first_name":"Randy","last_name":"Hlavac","middle_name":"","short_name":"hlavac","instructor_id":2685315,"id":659},{"first_name":"Andrew","last_name":"Gruen","middle_name":"","short_name":"andrewgruen","instructor_id":2685318,"id":660},{"first_name":"John","last_name":"Lavine","middle_name":"","short_name":"johnlavine","instructor_id":1841753,"id":532},{"first_name":"Rachel","last_name":"Mersey","middle_name":"Davis","short_name":"racheldavismersey","instructor_id":2685264,"id":661},{"first_name":"Jeremy","last_name":"Gilbert","middle_name":"","short_name":"gilbert","instructor_id":3307276,"id":879},{"first_name":"Edward","last_name":"Malthouse","middle_name":"","short_name":"malthouse","instructor_id":2685240,"id":657},{"first_name":"Emily","last_name":"Withrow","middle_name":"","short_name":"emilywithrow","instructor_id":2685294,"id":663},{"first_name":"Janice","last_name":"Castro","middle_name":"","short_name":"janicecastro","instructor_id":2685310,"id":664},{"first_name":"Steven","last_name":"Duke","middle_name":"","short_name":"stevenduke","instructor_id":2685284,"id":662},{"first_name":"Sue","last_name":"Alcock","middle_name":"","short_name":null,"instructor_id":1224295,"id":245},{"first_name":"Eric","last_name":"Rabkin","middle_name":"","short_name":null,"instructor_id":806928,"id":120},{"first_name":"David","last_name":"Wetherall","middle_name":"","short_name":null,"instructor_id":517478,"id":105},{"first_name":"Arvind","last_name":"Krishnamurthy","middle_name":"","short_name":"arvind","instructor_id":525208,"id":38},{"first_name":"John","last_name":"Zahorjan","middle_name":"","short_name":null,"instructor_id":1020740,"id":329},{"first_name":"Matthew","last_name":"Sparke","middle_name":"","short_name":"msparke","instructor_id":3471976,"id":938},{"first_name":"Ellen","last_name":"Moir","middle_name":"","short_name":"ellenmoir","instructor_id":3360910,"id":910},{"first_name":"Lynn","last_name":"Kepp","middle_name":"","short_name":"lynnkepp","instructor_id":611232,"id":907},{"first_name":"Hazel","last_name":"Genn","middle_name":"","short_name":null,"instructor_id":2603342,"id":504},{"first_name":"Adam","last_name":"Gearey","middle_name":"","short_name":"adamgearey","instructor_id":3680947,"id":1011},{"first_name":"Enrique","last_name":"Tam\u00e9s","middle_name":"","short_name":"enriquetames","instructor_id":2645293,"id":603},{"first_name":"Stan","last_name":"Deresinski","middle_name":"","short_name":"standeresinski","instructor_id":1166989,"id":558},{"first_name":"Yuval","last_name":"Harari","middle_name":"Noah","short_name":null,"instructor_id":1804614,"id":284},{"first_name":"Mayank","last_name":"Dutia","middle_name":"","short_name":null,"instructor_id":920057,"id":193},{"first_name":"Celine","last_name":"Caquineau","middle_name":"","short_name":null,"instructor_id":1016886,"id":59},{"first_name":"Don","last_name":"Hornstein","middle_name":"","short_name":null,"instructor_id":2688952,"id":674},{"first_name":"Cheryl","last_name":"Dennison Himmelfarb","middle_name":"","short_name":"cheryldennison","instructor_id":2722532,"id":716},{"first_name":"Peter","last_name":"Pronovost","middle_name":"J. ","short_name":"peterpronovost","instructor_id":3145522,"id":821},{"first_name":"Martin","last_name":"Kleinsteuber","middle_name":"","short_name":null,"instructor_id":2693792,"id":693},{"first_name":"Paul","last_name":"Bloom","middle_name":"","short_name":"paulbloom","instructor_id":1513337,"id":965},{"first_name":"Joe","last_name":"Warren","middle_name":"","short_name":null,"instructor_id":527518,"id":327},{"first_name":"Scott","last_name":"Rixner","middle_name":"","short_name":null,"instructor_id":726142,"id":328},{"first_name":"John","last_name":"Greiner","middle_name":"","short_name":null,"instructor_id":530929,"id":144},{"first_name":"Stephen","last_name":"Wong","middle_name":"","short_name":null,"instructor_id":695900,"id":754},{"first_name":"Hannes","last_name":"Leitgeb","middle_name":"","short_name":"hannesleitgeb","instructor_id":2512709,"id":340},{"first_name":"Stephan","last_name":"Hartmann","middle_name":"","short_name":null,"instructor_id":2582502,"id":342},{"first_name":"Sarah","last_name":"Kagan","middle_name":"","short_name":"sarahkagan","instructor_id":2789426,"id":726},{"first_name":"Anne","last_name":"Shoemaker","middle_name":"","short_name":"anneshoe","instructor_id":2947873,"id":756},{"first_name":"Pavel ","last_name":"Pevzner","middle_name":"","short_name":"pavelpevzner","instructor_id":1540981,"id":526},{"first_name":"Phillip","last_name":"Compeau","middle_name":"E. C.","short_name":"phillipcompeau","instructor_id":2658887,"id":610},{"first_name":"Nikolay","last_name":"Vyahhi","middle_name":"","short_name":"vyahhi","instructor_id":3542322,"id":975},{"first_name":"Jerusalem","last_name":"Makonnen","middle_name":"","short_name":null,"instructor_id":868795,"id":278},{"first_name":"Scott","last_name":"Page","middle_name":"E.","short_name":null,"instructor_id":785,"id":268},{"first_name":"Jack","last_name":"Matson","middle_name":"V.","short_name":"jmatson","instructor_id":1924714,"id":552},{"first_name":"Darrell","last_name":"Velegol","middle_name":"","short_name":"dvelegol","instructor_id":2644910,"id":572},{"first_name":"Kathryn","last_name":"Jablokow","middle_name":"W.","short_name":"kjablokow","instructor_id":2631338,"id":546},{"first_name":"Valerie","last_name":"Swigart","middle_name":"","short_name":"valerie","instructor_id":2258110,"id":844},{"first_name":"Michael","last_name":"Gold","middle_name":"","short_name":"mgold","instructor_id":1600503,"id":377},{"first_name":"Sergio","last_name":" Ortiz Vald\u00e9s","middle_name":"","short_name":"sergio","instructor_id":2645282,"id":589},{"first_name":"Dante B.","last_name":"Castro Solano","middle_name":"","short_name":"dbcastro","instructor_id":3231512,"id":1026},{"first_name":"Rafaela","last_name":"Bueckmann Diegoli","middle_name":"","short_name":"rdiegoli","instructor_id":2747070,"id":1025},{"first_name":"Charles","last_name":"Severance","middle_name":"","short_name":null,"instructor_id":122340,"id":82},{"first_name":"Caren","last_name":"Stalburg","middle_name":"","short_name":"carenstalburg","instructor_id":2705795,"id":727},{"first_name":"Michael","last_name":"Beach","middle_name":"","short_name":null,"instructor_id":1722827,"id":378},{"first_name":"Lisa","last_name":"Mazzola","middle_name":"","short_name":"lisamazzola","instructor_id":3219339,"id":892},{"first_name":"Michael","last_name":"Roth","middle_name":"S.","short_name":null,"instructor_id":804990,"id":237},{"first_name":"Owen","last_name":"Youngman","middle_name":"R.","short_name":"youngowen","instructor_id":2657356,"id":596},{"first_name":"Christopher","last_name":"Brinton","middle_name":"","short_name":"cbrinton","instructor_id":599445,"id":982},{"first_name":"Kenneth ","last_name":"Shropshire","middle_name":"L. ","short_name":null,"instructor_id":1894245,"id":352},{"first_name":"Lada","last_name":"Adamic","middle_name":"","short_name":null,"instructor_id":123682,"id":267},{"first_name":"Margaret","last_name":"Wooldridge","middle_name":"","short_name":"margaretwooldridge","instructor_id":2042576,"id":15},{"first_name":"Marnie","last_name":"Blewitt","middle_name":"","short_name":null,"instructor_id":1288295,"id":54},{"first_name":"Kim","last_name":"Rhoads","middle_name":"F.","short_name":"kimrhoads","instructor_id":3229025,"id":840},{"first_name":"Tim","last_name":"Roughgarden","middle_name":"","short_name":null,"instructor_id":768,"id":214},{"first_name":"Ryan","last_name":"Baker","middle_name":"S.J.d.","short_name":"ryanbaker","instructor_id":2093911,"id":484},{"first_name":"Matt","last_name":"McGarrity","middle_name":"","short_name":"mcgarrity","instructor_id":2255684,"id":782},{"first_name":"John","last_name":"Featherstone","middle_name":"","short_name":"johnfeatherstone","instructor_id":3237389,"id":849},{"first_name":"Hitoshi","last_name":"Murayama","middle_name":"","short_name":"murayama","instructor_id":2673437,"id":631},{"first_name":"Larry","last_name":"Foulke","middle_name":"","short_name":null,"instructor_id":1564078,"id":231},{"first_name":"Stephan","last_name":"Koplowitz","middle_name":"","short_name":null,"instructor_id":2531752,"id":303},{"first_name":"Jeannene","last_name":"Przyblyski","middle_name":"","short_name":"jeanneneprzy","instructor_id":2089332,"id":302},{"first_name":"Stefaan","last_name":"Van den Bogaert","middle_name":"","short_name":"stefaanvandenbogaert","instructor_id":1819928,"id":590},{"first_name":"Edwin","last_name":"Bakker","middle_name":"","short_name":"edwinbakker","instructor_id":2641217,"id":564},{"first_name":"Jennifer","last_name":"Carbrey","middle_name":"","short_name":null,"instructor_id":868977,"id":12},{"first_name":"Emma","last_name":"Jakoi","middle_name":"","short_name":null,"instructor_id":920567,"id":13},{"first_name":"Karen","last_name":"Head","middle_name":"","short_name":"khead","instructor_id":3011727,"id":768},{"first_name":"Lam Lung","last_name":"Yeung","middle_name":"","short_name":null,"instructor_id":1343630,"id":76},{"first_name":"King","last_name":"Chow","middle_name":"L.","short_name":null,"instructor_id":1358517,"id":56},{"first_name":"Pascal","last_name":"Van Hentenryck","middle_name":"","short_name":null,"instructor_id":1289035,"id":256},{"first_name":"Amy","last_name":"Rickman","middle_name":"D.","short_name":"arickman","instructor_id":2595360,"id":384},{"first_name":"John","last_name":"Jakicic","middle_name":"M.","short_name":null,"instructor_id":2595632,"id":385},{"first_name":"Tobias","last_name":"Kretschmer","middle_name":"","short_name":"tobiaskretschmer","instructor_id":2573718,"id":336},{"first_name":"Karen","last_name":"Charron","middle_name":"R.","short_name":null,"instructor_id":598777,"id":317},{"first_name":"Amber","last_name":"Cox","middle_name":"Bickford","short_name":null,"instructor_id":603309,"id":22},{"first_name":"Philip","last_name":"Klein","middle_name":"","short_name":null,"instructor_id":1234717,"id":243},{"first_name":"Sylvie","last_name":"M\u00e9l\u00e9ard","middle_name":"","short_name":"sylviemeleard","instructor_id":1914201,"id":714},{"first_name":"Jean-Ren\u00e9","last_name":"Chazottes","middle_name":"","short_name":"jrchazottes","instructor_id":2593255,"id":369},{"first_name":" Rolf ","last_name":"Strom-Olsen ","middle_name":"","short_name":"rolfstromolsen","instructor_id":2656811,"id":595},{"first_name":"Jason","last_name":"Freeman","middle_name":"A.","short_name":"freeman","instructor_id":1077292,"id":529},{"first_name":"Jason","last_name":"Hill","middle_name":"","short_name":"jasonhill","instructor_id":2570343,"id":521},{"first_name":"Lara","last_name":"Arch","middle_name":"","short_name":"laraarch","instructor_id":3510175,"id":951},{"first_name":"Chris","last_name":"Thompson","middle_name":"\"C. J.\"","short_name":"cjthompson","instructor_id":565747,"id":952},{"first_name":"Lisa","last_name":"Webber","middle_name":"","short_name":"lwebber","instructor_id":3510185,"id":953},{"first_name":"Jarrett","last_name":"Whitaker","middle_name":"Reid","short_name":"reidwhitaker","instructor_id":386687,"id":954},{"first_name":"Jeffrey","last_name":"Pomerantz","middle_name":"","short_name":null,"instructor_id":2690251,"id":688},{"first_name":"Evan","last_name":"Feldman","middle_name":"","short_name":null,"instructor_id":2694569,"id":694},{"first_name":"Lorenzo","last_name":"Cavallaro","middle_name":"","short_name":null,"instructor_id":1347691,"id":3},{"first_name":"Asher","last_name":" Susser","middle_name":"","short_name":"ashersusser","instructor_id":3467705,"id":937},{"first_name":"Duygu","last_name":"Atlas","middle_name":"","short_name":"duyguatlas","instructor_id":3596990,"id":977},{"first_name":"Daniel","last_name":"Chamovitz","middle_name":"","short_name":"chamovitz","instructor_id":3287177,"id":861},{"first_name":"Aviva ","last_name":"Katz","middle_name":"","short_name":"akatz","instructor_id":3708694,"id":1018},{"first_name":"Oded","last_name":" Lipschits","middle_name":"","short_name":"lipschits","instructor_id":3287070,"id":860},{"first_name":"Ido","last_name":"Koch","middle_name":"","short_name":"idokoch","instructor_id":3204080,"id":858},{"first_name":"Scott","last_name":"Plous","middle_name":"","short_name":"scottplous","instructor_id":1127341,"id":235},{"first_name":"Hossam","last_name":"Haick","middle_name":"","short_name":"hossamhaick","instructor_id":2444381,"id":1081},{"first_name":"Terry","last_name":"Talley","middle_name":"K.","short_name":"drterrytalley","instructor_id":3675391,"id":1002},{"first_name":"Larisa","last_name":"Enr\u00edquez","middle_name":"","short_name":"larisaev","instructor_id":1177458,"id":338},{"first_name":"Balaji","last_name":"Srinivasan","middle_name":"S.","short_name":"balajis","instructor_id":1845856,"id":45},{"first_name":"Vijay","last_name":"Pande","middle_name":"S.","short_name":"vijaypande","instructor_id":1853352,"id":224},{"first_name":"Barbara","last_name":"Conradt","middle_name":"","short_name":null,"instructor_id":2582522,"id":341},{"first_name":"J.","last_name":"Halderman","middle_name":"Alex","short_name":null,"instructor_id":715252,"id":269},{"first_name":"Ebrahim","last_name":"Afsah","middle_name":"","short_name":"afsah","instructor_id":2566181,"id":307},{"first_name":"Stephany","last_name":"Duda","middle_name":"","short_name":null,"instructor_id":240569,"id":289},{"first_name":"Paul","last_name":"Harris","middle_name":"","short_name":null,"instructor_id":1347429,"id":288},{"first_name":"Firas ","last_name":"Wehbe","middle_name":"","short_name":null,"instructor_id":1653154,"id":125},{"first_name":"Vincent","last_name":"Racaniello","middle_name":"","short_name":null,"instructor_id":2096804,"id":355},{"first_name":"Joseph","last_name":"Guglielmo","middle_name":"","short_name":null,"instructor_id":3408612,"id":929},{"first_name":"Lisa","last_name":"Kroon","middle_name":"A.","short_name":null,"instructor_id":3693651,"id":1032},{"first_name":"Todd","last_name":"Murphey","middle_name":"D.","short_name":"murphey","instructor_id":2658770,"id":599},{"first_name":"Petra","last_name":"Bonfert-Taylor","middle_name":"","short_name":"pbonfert","instructor_id":3491158,"id":1027},{"first_name":"Anders","last_name":"Pedersen","middle_name":"Gorm","short_name":"anders","instructor_id":2526797,"id":202},{"first_name":"Jonathan","last_name":"Biss","middle_name":"","short_name":"jonathanbiss","instructor_id":2675440,"id":636},{"first_name":"Dan","last_name":"Dickrell","middle_name":"","short_name":"dandickrell","instructor_id":3397716,"id":927},{"first_name":"Mar\u00eda Soledad","last_name":"Ram\u00edrez Montoya","middle_name":"","short_name":"solramirez","instructor_id":2645257,"id":575},{"first_name":"Jos\u00e9 Vladimir ","last_name":"Burgos Aguilar","middle_name":"","short_name":"vburgos","instructor_id":2645262,"id":576},{"first_name":"Anthony","last_name":"Robinson","middle_name":"C.","short_name":"arobinson","instructor_id":2560495,"id":531},{"first_name":"Melissa","last_name":"Loble","middle_name":"Joell","short_name":"mloble","instructor_id":1676603,"id":468},{"first_name":"","last_name":"","middle_name":"","short_name":null,"instructor_id":3401945,"id":925},{"first_name":"Cindy ","last_name":"Carbajal","middle_name":"","short_name":"cindyc","instructor_id":2333330,"id":707},{"first_name":"Antoine","last_name":"Geissbuhler","middle_name":"","short_name":"geissbuhler","instructor_id":2511245,"id":191},{"first_name":"Louis","last_name":"Loutan","middle_name":"","short_name":"loutan","instructor_id":2894378,"id":737},{"first_name":"Samantha","last_name":"Battams","middle_name":"","short_name":"battams","instructor_id":3096301,"id":805},{"first_name":"Didier","last_name":"Wernli","middle_name":"","short_name":"wernli","instructor_id":2581715,"id":797},{"first_name":"Slim","last_name":"Slama","middle_name":"","short_name":"slama","instructor_id":2590328,"id":799},{"first_name":"Rafael","last_name":"Ruiz De Castaneda","middle_name":"","short_name":"ruizdecastaneda","instructor_id":2918070,"id":798},{"first_name":"Christophe","last_name":"Chalamet","middle_name":"","short_name":"chalamet","instructor_id":2408877,"id":74},{"first_name":"Fran\u00e7ois","last_name":"Dermange","middle_name":"","short_name":"dermange","instructor_id":2604148,"id":507},{"first_name":"Michel","last_name":"Grandjean","middle_name":"","short_name":"grandjean","instructor_id":2513105,"id":505},{"first_name":"Sarah","last_name":"Nicolet","middle_name":"","short_name":"nicolet","instructor_id":2590461,"id":536},{"first_name":"Richard","last_name":"Boyatzis","middle_name":"","short_name":"richardboyatzis","instructor_id":2075897,"id":199},{"first_name":"Jonathan ","last_name":"Coopersmith","middle_name":"","short_name":"jonathancoopersmith","instructor_id":2675437,"id":635},{"first_name":"David","last_name":"Ludwig","middle_name":"","short_name":"davidludwig","instructor_id":2654261,"id":665},{"first_name":"Al","last_name":"Filreis","middle_name":"","short_name":null,"instructor_id":224886,"id":26},{"first_name":"James","last_name":"Green","middle_name":"V.","short_name":"jvgreen","instructor_id":1312728,"id":271},{"first_name":"Charmaine","last_name":"Williams","middle_name":"","short_name":null,"instructor_id":882099,"id":7},{"first_name":"Kenneth ","last_name":"Hale","middle_name":"M. ","short_name":"kenhale","instructor_id":1293473,"id":149},{"first_name":"Nicole","last_name":"Kwiek","middle_name":"Cartwright","short_name":"nicolekwiek","instructor_id":1293448,"id":318},{"first_name":"Katie","last_name":"Ferraro","middle_name":"","short_name":null,"instructor_id":994329,"id":279}],"courses":[{"start_month":4,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":23,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":2,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":16},{"start_month":5,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":28,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":6,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":18},{"start_month":3,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":12,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":7,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":20},{"start_month":3,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":19,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":3,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":22},{"start_month":3,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":12,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":9,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":24},{"start_month":3,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":12,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":8,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":26},{"start_month":2,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":11,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":30},{"start_month":null,"status":1,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":12,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":32},{"start_month":3,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":19,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":20,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":46},{"start_month":4,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":23,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":13,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":52},{"start_month":4,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":23,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":14,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":54},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":19,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":60},{"start_month":4,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":23,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":15,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":66},{"start_month":4,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":23,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":16,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":76},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":10,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":22,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":80},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":3,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":82},{"start_month":6,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":11,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":8,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":84},{"start_month":1,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":20,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":86},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":7,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":88},{"start_month":6,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":11,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":9,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":90},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":3,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":11,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":94},{"start_month":6,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":11,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":23,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":96},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":17,"duration_string":"14 weeks","signature_track_registration_open":false,"topic_id":45,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":98},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":30,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":24,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":100},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":3,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":25,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":102},{"start_month":8,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":12,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":26,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":104},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":38,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":108},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":3,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":39,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":110},{"start_month":7,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":23,"duration_string":"13 weeks","signature_track_registration_open":false,"topic_id":40,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":112},{"start_month":7,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":23,"duration_string":"14 weeks","signature_track_registration_open":false,"topic_id":41,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":114},{"start_month":7,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":23,"duration_string":"13 weeks","signature_track_registration_open":false,"topic_id":42,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":116},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":43,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":118},{"start_month":7,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":23,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":28,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":120},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":29,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":122},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":"2013-01-07","start_day":7,"duration_string":"13 weeks","signature_track_registration_open":false,"topic_id":30,"signature_track_close_time":"2013-02-27","eligible_for_signature_track":true,"id":124},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":10,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":31,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":126},{"start_month":8,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":27,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":32,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":128},{"start_month":6,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":25,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":33,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":130},{"start_month":6,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":25,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":34,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":132},{"start_month":6,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":25,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":35,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":134},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":20,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":36,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":136},{"start_month":10,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":15,"duration_string":"14 weeks","signature_track_registration_open":false,"topic_id":44,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":138},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"4 - 5 weeks","signature_track_registration_open":false,"topic_id":37,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":140},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":17,"duration_string":"14 weeks","signature_track_registration_open":false,"topic_id":48,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":148},{"start_month":10,"status":1,"start_year":2012,"signature_track_open_time":null,"start_day":1,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":16,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":150},{"start_month":8,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":20,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":2,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":152},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":13,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":154},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":14,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":156},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":15,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":158},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":6,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":164},{"start_month":8,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":27,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":9,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":170},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":8,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":172},{"start_month":9,"status":1,"start_year":2012,"signature_track_open_time":null,"start_day":17,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":124,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":176},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":50,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":178},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-15","start_day":20,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":51,"signature_track_close_time":"2013-06-10","eligible_for_signature_track":true,"id":180},{"start_month":10,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":15,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":88,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":204},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":53,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":216},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":"2013-04-12","start_day":15,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":54,"signature_track_close_time":"2013-05-01","eligible_for_signature_track":true,"id":218},{"start_month":2,"status":0,"start_year":2013,"signature_track_open_time":"2013-02-25","start_day":25,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":55,"signature_track_close_time":"2013-03-25","eligible_for_signature_track":true,"id":220},{"start_month":10,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":10,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":56,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":222},{"start_month":11,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":27,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":57,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":224},{"start_month":11,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":26,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":58,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":226},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":"2013-04-03","start_day":8,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":59,"signature_track_close_time":"2013-04-30","eligible_for_signature_track":true,"id":228},{"start_month":2,"status":0,"start_year":2013,"signature_track_open_time":"2013-02-11","start_day":11,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":65,"signature_track_close_time":"2013-02-26","eligible_for_signature_track":true,"id":230},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":"2013-01-28","start_day":28,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":67,"signature_track_close_time":"2013-02-11","eligible_for_signature_track":true,"id":232},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":69,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":234},{"start_month":10,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":22,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":62,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":238},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":23,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":72,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":246},{"start_month":10,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":29,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":78,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":250},{"start_month":9,"status":1,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":60,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":252},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":66,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":254},{"start_month":10,"status":1,"start_year":2012,"signature_track_open_time":null,"start_day":1,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":77,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":256},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":80,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":258},{"start_month":2,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":70,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":260},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":85,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":262},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":84,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":266},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":12,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":91,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":270},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"10 weeks ","signature_track_registration_open":false,"topic_id":92,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":276},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":93,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":278},{"start_month":2,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":18,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":121,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":280},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":94,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":284},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":114,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":290},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":61,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":294},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":"2013-01-21","start_day":21,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":90,"signature_track_close_time":"2013-02-22","eligible_for_signature_track":true,"id":296},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":63,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":300},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":68,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":302},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":23,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":71,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":304},{"start_month":10,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":22,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":74,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":306},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":18,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":116,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":308},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":98,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":310},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":110,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":312},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":115,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":314},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":89,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":316},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":119,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":318},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":15,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":122,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":322},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":95,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":324},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":26,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":103,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":326},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":96,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":328},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":19,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":97,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":330},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":100,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":336},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":102,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":340},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":14,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":105,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":344},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":106,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":346},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":14,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":117,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":352},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":81,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":356},{"start_month":1,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":82,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":358},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":123,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":360},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":87,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":362},{"start_month":10,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":22,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":86,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":364},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":108,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":366},{"start_month":10,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":22,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":126,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":368},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":125,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":370},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":23,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":372},{"start_month":12,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":3,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":128,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":374},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":15,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":127,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":376},{"start_month":null,"status":1,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":16,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":378},{"start_month":null,"status":1,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":13,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":380},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":130,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":382},{"start_month":11,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":28,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":129,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":384},{"start_month":1,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":14,"duration_string":"15 weeks","signature_track_registration_open":false,"topic_id":132,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":386},{"start_month":8,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":27,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":136,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":394},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":137,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":396},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":"2013-01-28","start_day":28,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":138,"signature_track_close_time":"2013-02-19","eligible_for_signature_track":true,"id":398},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":131,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":402},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":135,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":408},{"start_month":12,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":1,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":83,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":410},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":139,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":412},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":140,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":414},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":141,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":416},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":143,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":418},{"start_month":2,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":17,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":144,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":422},{"start_month":8,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":27,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":145,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":432},{"start_month":9,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":4,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":148,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":452},{"start_month":9,"status":1,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":147,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":454},{"start_month":1,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":14,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":153,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":462},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":29,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":154,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":468},{"start_month":9,"status":1,"start_year":2012,"signature_track_open_time":null,"start_day":24,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":157,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":472},{"start_month":1,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":160,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970193},{"start_month":2,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":167,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970195},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":168,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970196},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":170,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970197},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":"2013-02-28","start_day":1,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":42,"signature_track_close_time":"2013-03-22","eligible_for_signature_track":true,"id":970198},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":171,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970199},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":24,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":176,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970200},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":33,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970201},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":9,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":189,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970202},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":34,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970205},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":35,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970206},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":28,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970208},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":9,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":192,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970212},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":21,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":205,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970215},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":"2013-01-28","start_day":28,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":208,"signature_track_close_time":"2013-02-25","eligible_for_signature_track":true,"id":970216},{"start_month":2,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":202,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970218},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":26,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":211,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970220},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":179,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970221},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":178,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970222},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":181,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970223},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":"2013-04-24","start_day":29,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":201,"signature_track_close_time":"2013-05-14","eligible_for_signature_track":true,"id":970224},{"start_month":2,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":203,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970225},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":"2013-03-17","start_day":18,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":193,"signature_track_close_time":"2013-04-08","eligible_for_signature_track":true,"id":970226},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":18,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":221,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970227},{"start_month":2,"status":1,"start_year":2013,"signature_track_open_time":"2013-02-04","start_day":4,"duration_string":"14 weeks","signature_track_registration_open":false,"topic_id":177,"signature_track_close_time":"2013-02-27","eligible_for_signature_track":true,"id":970228},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":"2013-03-25","start_day":25,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":188,"signature_track_close_time":"2013-04-09","eligible_for_signature_track":true,"id":970229},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":182,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970230},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":190,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970234},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":186,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970235},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":29,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":185,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970236},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":12,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":184,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970237},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":173,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970238},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":18,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":174,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970239},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":19,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":172,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970240},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":31,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":175,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970241},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":200,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970242},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":"2013-01-28","start_day":28,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":210,"signature_track_close_time":"2013-02-25","eligible_for_signature_track":true,"id":970243},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":29,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":219,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970244},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":29,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":218,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970245},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":9,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":161,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970246},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":164,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970247},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":26,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":165,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970248},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":10,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":163,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970249},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":15,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":162,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970250},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-06-08","start_day":10,"duration_string":"6 weeks","signature_track_registration_open":true,"topic_id":228,"signature_track_close_time":"2013-06-25","eligible_for_signature_track":true,"id":970251},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-15","start_day":20,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":226,"signature_track_close_time":"2013-06-11","eligible_for_signature_track":true,"id":970253},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-07","start_day":1,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":206,"signature_track_close_time":"2013-05-22","eligible_for_signature_track":true,"id":970254},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-06-13","start_day":17,"duration_string":"6 weeks","signature_track_registration_open":true,"topic_id":232,"signature_track_close_time":"2013-07-02","eligible_for_signature_track":true,"id":970255},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-15","start_day":3,"duration_string":"8 weeks","signature_track_registration_open":true,"topic_id":233,"signature_track_close_time":"2013-06-25","eligible_for_signature_track":true,"id":970256},{"start_month":2,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":18,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":223,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970258},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":207,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970259},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":198,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970260},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":204,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970261},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":220,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970262},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":222,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970263},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":"2013-04-29","start_day":30,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":215,"signature_track_close_time":"2013-05-21","eligible_for_signature_track":true,"id":970264},{"start_month":null,"status":1,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":243,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970265},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-06-21","start_day":24,"duration_string":"6 weeks","signature_track_registration_open":true,"topic_id":245,"signature_track_close_time":"2013-07-09","eligible_for_signature_track":true,"id":970266},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-06-21","start_day":24,"duration_string":"6 weeks","signature_track_registration_open":true,"topic_id":244,"signature_track_close_time":"2013-07-09","eligible_for_signature_track":true,"id":970267},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":234,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970268},{"start_month":5,"status":0,"start_year":2013,"signature_track_open_time":"2013-05-07","start_day":6,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":235,"signature_track_close_time":"2013-05-21","eligible_for_signature_track":true,"id":970269},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":196,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970270},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":242,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970271},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":5,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":229,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970272},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":"2013-03-31","start_day":31,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":197,"signature_track_close_time":"2013-04-23","eligible_for_signature_track":true,"id":970273},{"start_month":2,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":24,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":224,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970274},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":9,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":246,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970275},{"start_month":2,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":24,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":225,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970276},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"3 weeks","signature_track_registration_open":false,"topic_id":214,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970277},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":217,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970278},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":10,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":216,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970279},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":236,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970281},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":"2013-03-21","start_day":18,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":247,"signature_track_close_time":"2013-04-08","eligible_for_signature_track":true,"id":970282},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":"2013-03-23","start_day":24,"duration_string":"15 weeks","signature_track_registration_open":false,"topic_id":237,"signature_track_close_time":"2013-04-16","eligible_for_signature_track":true,"id":970284},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":239,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970285},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":240,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970286},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":41,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970287},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"15 weeks","signature_track_registration_open":false,"topic_id":40,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970288},{"start_month":11,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":5,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":9,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970294},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":14,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":9,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970296},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":11,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":260,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970300},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":254,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970301},{"start_month":2,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":26,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970302},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-29","start_day":3,"duration_string":"15 weeks","signature_track_registration_open":true,"topic_id":40,"signature_track_close_time":"2013-06-25","eligible_for_signature_track":true,"id":970308},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":2,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970311},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":268,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970312},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":"2013-04-01","start_day":1,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":32,"signature_track_close_time":"2013-04-17","eligible_for_signature_track":true,"id":970314},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":24,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":145,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970315},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":219,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970319},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":229,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970329},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":24,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":80,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970330},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":12,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":278,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970336},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":"2013-04-07","start_day":8,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":277,"signature_track_close_time":"2013-04-30","eligible_for_signature_track":true,"id":970344},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":"2013-01-04","start_day":4,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":56,"signature_track_close_time":"2013-02-08","eligible_for_signature_track":true,"id":970351},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":285,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970352},{"start_month":2,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":288,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970353},{"start_month":2,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":18,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":290,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970354},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":10,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":289,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970358},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":"2013-06-18","start_day":7,"duration_string":"20 weeks","signature_track_registration_open":true,"topic_id":292,"signature_track_close_time":"2013-07-16","eligible_for_signature_track":true,"id":970359},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"15 weeks","signature_track_registration_open":false,"topic_id":282,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970360},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":11,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":136,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970361},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":2,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":293,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970362},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":"2013-04-19","start_day":22,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":295,"signature_track_close_time":"2013-05-07","eligible_for_signature_track":true,"id":970365},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":30,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":297,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970370},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":17,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":300,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970374},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":22,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970375},{"start_month":5,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":304,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970380},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":15,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970382},{"start_month":12,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":17,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":148,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970383},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":102,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970386},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":103,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970387},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":20,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":307,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970388},{"start_month":2,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"19 weeks","signature_track_registration_open":false,"topic_id":48,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970389},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":"2013-04-14","start_day":15,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":88,"signature_track_close_time":"2013-05-07","eligible_for_signature_track":true,"id":970391},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":8,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":3,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970393},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":26,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":311,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970399},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":26,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970400},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":17,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":312,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970401},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":17,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":313,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970402},{"start_month":2,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":17,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":314,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970403},{"start_month":1,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":2,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":63,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970404},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":16,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":68,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970405},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":121,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970410},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":18,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":315,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970415},{"start_month":2,"status":1,"start_year":2013,"signature_track_open_time":"2013-02-04","start_day":4,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":53,"signature_track_close_time":"2013-02-25","eligible_for_signature_track":true,"id":970426},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":"2013-03-24","start_day":25,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":322,"signature_track_close_time":"2013-04-16","eligible_for_signature_track":true,"id":970428},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":6,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":328,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970429},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":329,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970433},{"start_month":2,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":333,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970437},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":5,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":337,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970445},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":31,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":6,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970447},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":74,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970448},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":20,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970449},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":"2013-03-17","start_day":18,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":327,"signature_track_close_time":"2013-04-09","eligible_for_signature_track":true,"id":970454},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":60,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970455},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":116,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970457},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":24,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":78,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970459},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":62,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970460},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":334,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970465},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":"2013-03-08","start_day":4,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":38,"signature_track_close_time":"2013-03-25","eligible_for_signature_track":true,"id":970466},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":"2013-03-01","start_day":4,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":11,"signature_track_close_time":"2013-03-25","eligible_for_signature_track":true,"id":970475},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":27,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970478},{"start_month":2,"status":0,"start_year":2013,"signature_track_open_time":"2013-02-21","start_day":23,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":86,"signature_track_close_time":"2013-03-18","eligible_for_signature_track":true,"id":970485},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"0 weeks","signature_track_registration_open":false,"topic_id":44,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970486},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":"2013-04-24","start_day":29,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":125,"signature_track_close_time":"2013-05-21","eligible_for_signature_track":true,"id":970487},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":"2013-04-15","start_day":29,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":126,"signature_track_close_time":"2013-05-21","eligible_for_signature_track":true,"id":970488},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":"2013-04-15","start_day":22,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":29,"signature_track_close_time":"2013-05-14","eligible_for_signature_track":true,"id":970489},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":31,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970490},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":9,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":356,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970496},{"start_month":3,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":124,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970506},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":347,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970508},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":200,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970509},{"start_month":2,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":11,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":16,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970514},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"13 weeks","signature_track_registration_open":false,"topic_id":368,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970515},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":5,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":354,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970516},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":10,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":371,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970518},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":376,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970523},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":"2013-04-18","start_day":19,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":378,"signature_track_close_time":"2013-05-10","eligible_for_signature_track":true,"id":970525},{"start_month":6,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":384,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970528},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-29","start_day":3,"duration_string":"11 weeks","signature_track_registration_open":true,"topic_id":41,"signature_track_close_time":"2013-06-25","eligible_for_signature_track":true,"id":970529},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":385,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970530},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":24,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":367,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970534},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":11,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":148,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970535},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":11,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":95,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970536},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":102,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970537},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":96,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970538},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":96,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970539},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":11,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":103,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970540},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":89,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970549},{"start_month":5,"status":0,"start_year":2013,"signature_track_open_time":"2013-05-03","start_day":3,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":393,"signature_track_close_time":"2013-05-17","eligible_for_signature_track":true,"id":970556},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":98,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970558},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":369,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970560},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":405,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970561},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"15 weeks","signature_track_registration_open":false,"topic_id":407,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970563},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":30,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":415,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970567},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":25,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970574},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":430,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970576},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":436,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970577},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":445,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970580},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":417,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970582},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":17,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":418,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970583},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":6,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":413,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970584},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":419,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970585},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":15,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":420,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970586},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":21,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":425,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970588},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":23,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":24,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970589},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":15,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":433,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970590},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":21,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":404,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970591},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":2,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":386,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970592},{"start_month":5,"status":0,"start_year":2013,"signature_track_open_time":"2013-05-17","start_day":20,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":381,"signature_track_close_time":"2013-06-11","eligible_for_signature_track":true,"id":970593},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":459,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970594},{"start_month":2,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":3,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":400,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970595},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":399,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970596},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-17","start_day":20,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":382,"signature_track_close_time":"2013-06-11","eligible_for_signature_track":true,"id":970598},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-28","start_day":31,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":380,"signature_track_close_time":"2013-06-20","eligible_for_signature_track":true,"id":970599},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":402,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970600},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":403,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970601},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":5,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":391,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970602},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":432,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970603},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":16,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":421,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970604},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":30,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":428,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970605},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":20,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":408,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970607},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":401,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970612},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":465,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970613},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":460,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970614},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-30","start_day":3,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":431,"signature_track_close_time":"2013-06-18","eligible_for_signature_track":true,"id":970615},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":426,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970616},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":21,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":427,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970617},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":14,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":383,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970621},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":472,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970622},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":13,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":435,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970623},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":442,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970628},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":8,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":440,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970629},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":434,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970630},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":451,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970633},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":455,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970634},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":471,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970636},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":462,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970637},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":441,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970641},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":446,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970642},{"start_month":12,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":2,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":438,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970644},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":21,"duration_string":"","signature_track_registration_open":false,"topic_id":447,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970645},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":467,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970646},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":450,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970647},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":461,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970648},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":484,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970650},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":448,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970651},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":30,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":398,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970652},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":477,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970653},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":2,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":128,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970655},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":488,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970656},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-01","start_day":1,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":463,"signature_track_close_time":"2013-05-15","eligible_for_signature_track":true,"id":970658},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":409,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970660},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":489,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970661},{"start_month":2,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":457,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970662},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":5,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":464,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970663},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":475,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970664},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":2,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":458,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970666},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":10,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":480,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970667},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":487,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970669},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-29","start_day":3,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":476,"signature_track_close_time":"2013-06-18","eligible_for_signature_track":true,"id":970671},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-11","start_day":13,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":478,"signature_track_close_time":"2013-05-28","eligible_for_signature_track":true,"id":970672},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-01","start_day":1,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":466,"signature_track_close_time":"2013-05-22","eligible_for_signature_track":true,"id":970677},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":29,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":71,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970679},{"start_month":12,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":2,"duration_string":"13 weeks","signature_track_registration_open":false,"topic_id":456,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970680},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":492,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970682},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":485,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970685},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-09","start_day":6,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":498,"signature_track_close_time":"2013-05-21","eligible_for_signature_track":true,"id":970687},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":499,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970688},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":500,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970690},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":501,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970692},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":29,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":422,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970696},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":410,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970697},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":12,"duration_string":"14 weeks","signature_track_registration_open":false,"topic_id":503,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970698},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":14,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":504,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970699},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":23,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":505,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970700},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":506,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970701},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":443,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970702},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":494,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970703},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":493,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970704},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":15,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":482,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970705},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":483,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970706},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":508,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970707},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":13,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":94,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970708},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":114,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970709},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":115,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970710},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":497,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970711},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":495,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970712},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":30,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":486,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970713},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":496,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970715},{"start_month":12,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":509,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970716},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":110,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970719},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":108,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970720},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":474,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970721},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":8,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":453,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970724},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":30,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":439,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970725},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":439,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970726},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":24,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":512,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970727},{"start_month":4,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":394,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970736},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":53,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970737},{"start_month":4,"status":0,"start_year":2013,"signature_track_open_time":"2013-04-03","start_day":8,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":138,"signature_track_close_time":"2013-04-30","eligible_for_signature_track":true,"id":970742},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":9,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970748},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":129,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970755},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":367,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970758},{"start_month":3,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":11,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":136,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970759},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":72,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970761},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":22,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":429,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970762},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":25,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":524,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970764},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":13,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":469,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970775},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-29","start_day":1,"duration_string":"11 weeks","signature_track_registration_open":true,"topic_id":42,"signature_track_close_time":"2013-06-25","eligible_for_signature_track":true,"id":970777},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-29","start_day":3,"duration_string":"10 weeks","signature_track_registration_open":true,"topic_id":11,"signature_track_close_time":"2013-06-25","eligible_for_signature_track":true,"id":970778},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":38,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970779},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":136,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970780},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-04-17","start_day":20,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":168,"signature_track_close_time":"2013-06-04","eligible_for_signature_track":true,"id":970786},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":6,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":411,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970788},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":243,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970792},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":179,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970824},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":39,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970825},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":20,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":135,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970826},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":8,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970827},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":526,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970828},{"start_month":4,"status":0,"start_year":2012,"signature_track_open_time":null,"start_day":1,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":81,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970829},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-07","start_day":24,"duration_string":"6 weeks","signature_track_registration_open":true,"topic_id":67,"signature_track_close_time":"2013-07-08","eligible_for_signature_track":true,"id":970830},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":91,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970833},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":347,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970840},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":27,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":537,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970845},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-08","start_day":26,"duration_string":"6 weeks","signature_track_registration_open":true,"topic_id":357,"signature_track_close_time":"2013-09-09","eligible_for_signature_track":true,"id":970846},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":527,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970848},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":3,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":56,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970850},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":24,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":105,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970859},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":117,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970860},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":5,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":582,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970861},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":16,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":203,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970864},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":449,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970868},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":449,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970869},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":449,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970870},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":449,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970871},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":584,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970874},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"3 weeks","signature_track_registration_open":false,"topic_id":598,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970878},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"3 weeks","signature_track_registration_open":false,"topic_id":599,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970879},{"start_month":5,"status":1,"start_year":2013,"signature_track_open_time":"2013-05-09","start_day":24,"duration_string":"13 weeks","signature_track_registration_open":false,"topic_id":30,"signature_track_close_time":"2013-06-13","eligible_for_signature_track":true,"id":970882},{"start_month":9,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":17,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":147,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970888},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":26,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":58,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970892},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"3 weeks","signature_track_registration_open":false,"topic_id":614,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970899},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"3 weeks","signature_track_registration_open":false,"topic_id":616,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970901},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":620,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970904},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":29,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":607,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970905},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":11,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":621,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970906},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":9,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":594,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970907},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":595,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970908},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":596,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970909},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":6,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":623,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970910},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":5,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":631,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970911},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":613,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970912},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":631,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970913},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":632,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970914},{"start_month":2,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":632,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970915},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":633,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970916},{"start_month":4,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":633,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970917},{"start_month":2,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":634,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970918},{"start_month":6,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":634,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970919},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":622,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970921},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":639,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970923},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":21,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":640,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970924},{"start_month":4,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":641,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970925},{"start_month":8,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":641,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970926},{"start_month":6,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":642,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970927},{"start_month":10,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":642,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970928},{"start_month":9,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":643,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970929},{"start_month":11,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":644,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970930},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":624,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970931},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":636,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970932},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":27,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":600,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970933},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":15,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":635,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970934},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":655,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970936},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":637,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970937},{"start_month":3,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":10,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":234,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970938},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":63,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970940},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":"2013-06-21","start_day":1,"duration_string":"6 weeks","signature_track_registration_open":true,"topic_id":591,"signature_track_close_time":"2013-10-15","eligible_for_signature_track":true,"id":970947},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":"2013-06-21","start_day":1,"duration_string":"8 weeks","signature_track_registration_open":true,"topic_id":592,"signature_track_close_time":"2013-10-15","eligible_for_signature_track":true,"id":970948},{"start_month":2,"status":1,"start_year":2015,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":643,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970951},{"start_month":4,"status":1,"start_year":2015,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":644,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970952},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":15,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":45,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970953},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":91,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970957},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":1,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":677,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970961},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"15 weeks","signature_track_registration_open":false,"topic_id":678,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970962},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":684,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970968},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":686,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970970},{"start_month":2,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":685,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970971},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":433,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970972},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":228,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970973},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":688,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970974},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":689,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970975},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":148,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970978},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":3,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":102,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970979},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":103,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970980},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":95,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970981},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":620,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970985},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":9,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":679,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":970990},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"","signature_track_registration_open":false,"topic_id":679,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":970991},{"start_month":9,"status":0,"start_year":2013,"signature_track_open_time":null,"start_day":2,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":124,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971004},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":6,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":699,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971007},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":41,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971012},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"15 weeks","signature_track_registration_open":false,"topic_id":40,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971013},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":42,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971014},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":11,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971015},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":38,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971016},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":566,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971021},{"start_month":6,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":17,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":9,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971022},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":2,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":254,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971029},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":29,"duration_string":"14 weeks","signature_track_registration_open":false,"topic_id":177,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971037},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"13 weeks","signature_track_registration_open":false,"topic_id":30,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":971039},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":7,"duration_string":"9 weeks","signature_track_registration_open":false,"topic_id":88,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971041},{"start_month":8,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":5,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":55,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971043},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":"2013-06-21","start_day":19,"duration_string":"6 weeks","signature_track_registration_open":true,"topic_id":222,"signature_track_close_time":"2013-08-02","eligible_for_signature_track":true,"id":971044},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":19,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":220,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971045},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":69,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971049},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":21,"duration_string":"6 weeks","signature_track_registration_open":false,"topic_id":729,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971056},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":2,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":193,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971057},{"start_month":11,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":4,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":703,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971063},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":27,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":704,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971064},{"start_month":4,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":7,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":705,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971065},{"start_month":5,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":12,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":706,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971066},{"start_month":1,"status":0,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"5 weeks","signature_track_registration_open":false,"topic_id":190,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971069},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":100,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":971078},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":57,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971082},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":126,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":971091},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":247,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971094},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":300,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":971096},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":499,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971098},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":492,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971099},{"start_month":1,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":755,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971100},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"10 weeks","signature_track_registration_open":false,"topic_id":755,"signature_track_close_time":null,"eligible_for_signature_track":null,"id":971101},{"start_month":10,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":28,"duration_string":"8 weeks","signature_track_registration_open":false,"topic_id":463,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971106},{"start_month":7,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":null,"duration_string":"7 weeks","signature_track_registration_open":false,"topic_id":68,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971111},{"start_month":3,"status":1,"start_year":2014,"signature_track_open_time":null,"start_day":17,"duration_string":"4 weeks","signature_track_registration_open":false,"topic_id":154,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971112},{"start_month":null,"status":0,"start_year":null,"signature_track_open_time":null,"start_day":null,"duration_string":"12 weeks","signature_track_registration_open":false,"topic_id":322,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971115},{"start_month":9,"status":1,"start_year":2013,"signature_track_open_time":null,"start_day":20,"duration_string":"11 weeks","signature_track_registration_open":false,"topic_id":206,"signature_track_close_time":null,"eligible_for_signature_track":false,"id":971123}]}
\ No newline at end of file
diff --git a/data/outcomes.xml b/data/outcomes.xml
new file mode 100644
index 0000000..90dd189
--- /dev/null
+++ b/data/outcomes.xml
@@ -0,0 +1,16812 @@
+
+Computer Science Curricula 2013Following a roughly 10 year cycle, the ACM and IEEE Computer Society jointly sponsor the development of a Computing Curricula volume on Computer Science. These volumes have helped to set international curricular guidelines for undergraduate programs in computing. In the summer of 2010, planning for the next volume in the series, Computer Science 2013 (CS2013), began.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Algorithms and Complexity (AL)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Architecture and Organization (AR)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Computational Science (CN)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Discrete Structures (DS)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Graphics and Visualization (GV)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Human-Computer Interaction (HC)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Information Assurance and Security (IAS)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Information Management (IM)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Intelligent Systems (IS)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Networking and Communication (NC)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Operating Systems (OS)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Platform-Based Development (PBD)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parallel and Distributed Computing (PD)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Programming Languages (PL)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Software Development Fundamentals (SDF)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Software Engineering (SE)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Systems Fundamentals (SF)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Social and Professional Practice (SP)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AL-Basic Analysis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AL-Algorithmic Strategies
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AL-Fundamental Data Structures and Algorithms
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AL-Basic Automata Computability and Complexity
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AL-Advanced Computational Complexity
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AL-Advanced Automata Theory and Computability
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AL-Advanced Data Structures Algorithms and Analysis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AR-Digital logic and digital systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AR-Machine-level representation of data
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AR-Assembly level machine organization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AR-Memory system organization and architecture
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AR-Interfacing and communication
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AR-Functional organization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AR-Multiprocessing and alternative architectures
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AR-Performance enhancements
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CN-Fundamentals
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CN-Modeling and Simulation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CN-Processing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CN-Interactive Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CN-Data, Information, and Knowledge
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DS-Sets, Relations, and Functions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DS-Basic Logic
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DS-Proof Techniques
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DS-Basics of Counting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DS-Graphs and Trees
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DS-Discrete Probability
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GV-Fundamental Concepts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GV-Basic Rendering
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GV-Geometric Modeling
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GV-Advanced Rendering
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GV-Computer Animation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GV-Visualization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HC-Foundations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HC-Designing Interaction
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HC-Programming Interactive Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HC-User-centered design and testing [elective]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HC-Design for non-mouse interfaces
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HC-Collaboration and communication
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HC-Statistical methods for HCI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HC-Human factors and security
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HC-Design-oriented HCI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HC-Mixed, Augmented and Virtual Reality
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IAS-Fundamental Concepts
+
+
+
+
+
+
+
+
+ IAS-Network Security
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IAS-Cryptography
+
+
+
+
+
+
+
+
+ IAS-Risk Management
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IAS-Security Policy and Governance
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IAS- Digital Forensics
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IAS-Security Architecture and Systems Administration
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IAS-Secure Software Design and Engineering
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Information Management Concepts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Database Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Data Modeling
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Indexing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Relational Databases
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Query Languages
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Transaction Processing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Distributed Databases
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Physical Database Design
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Data Mining
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IM-Information Storage and Retrieval
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Fundamental Issues
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Basic Search Strategies
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Basic Knowledge Representation and Reasoning
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Basic Machine Learning
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Advanced Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Advanced Representation and Reasoning
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Reasoning Under Uncertainty
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Agents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Natural Language Processing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Advanced Machine Learning
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Robotics
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IS-Perception and Computer Vision
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NC-Introduction
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NC-Networked Applications
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NC-Reliable Data Delivery
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NC-Routing And Forwarding
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NC-Local Area Networks
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NC-Resource Allocation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NC-Mobility
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-Overview of Operating Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-Operating System Principles
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-Concurrency
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-Scheduling and Dispatch
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-Memory Management
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-Security and Protection
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-Virtual Machines
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-Device Management
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-File Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-Real Time and Embedded Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-Fault Tolerance
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ OS-System Performance Evaluation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PBD-Introduction
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PBD-Web Platforms
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PBD-Mobile Platforms
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PBD-Industrial Platforms
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PBD-Game Platforms
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PD-Parallelism Fundamentals
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PD-Parallel Decomposition
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PD-Communication and Coordination
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PD-Parallel Algorithms, Analysis, and Programming
+
+
+
+
+
+
+
+
+ PD-Parallel Architecture
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PD-Parallel Performance
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PD-Distributed Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PD-Formal Models and Semantics
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Object-Oriented Programming
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Functional Programming
+
+
+
+
+
+
+
+
+ PL-Event-Driven and Reactive Programming
+
+
+
+
+
+
+
+
+ PL-Basic Type Systems
+
+
+
+
+
+
+
+
+ PL-Program Representation
+
+
+
+
+
+
+
+
+ PL-Language Translation and Execution
+
+
+
+
+
+
+
+
+ PL-Syntax Analysis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Compiler Semantic Analysis
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Code Generation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Runtime Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Static Analysis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Advanced Programming Constructs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Concurrency and Parallelism
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Type Systems
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Formal Semantics
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Language Pragmatics
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PL-Logic Programming
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SDF-Algorithms and Design
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SDF-Fundamental Programming Concepts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SDF-Fundamental Data Structures
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SDF-Development Methods
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SE-Software Processes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SE-Software Project Management
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SE-Tools and Environments
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SE-Requirements Engineering
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SE-Software Design
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SE-Software Construction
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SE-Software Verification Validation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SE-Software Evolution
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SE-Formal Methods
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SE-Software Reliability
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SF-Computational Paradigms
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SF-Cross-Layer Communications
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SF-State-State Transition-State Machines
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SF-System Support for Parallelism
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SF-Performance
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SF-Resource Allocation and Scheduling
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SF-Proximity
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SF-Virtualization and Isolation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SF-Reliability through Redundancy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SP-Social Context
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SP-Analytical Tools
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SP-Professional Ethics
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Explain what is meant by best, average, and worst case behavior of an algorithm
+
+
+
+
+
+
+
+
+ Determine informally the time and space complexity of simple algorithms
+
+
+
+
+
+
+
+
+ Understand the formal definition of big O
+
+
+
+
+
+
+
+
+ List and contrast standard complexity classes
+
+
+
+
+
+
+
+
+ Give examples that illustrate time-space trade-offs of algorithms
+
+
+
+
+
+
+
+
+ Use big O notation formally to give asymptotic upper bounds on time and space complexity of algorithms
+
+
+
+
+
+
+
+
+ Use big O notation formally to give average case bounds on time complexity of algorithms.
+
+
+
+
+
+
+
+
+ Explain the use of big omega, big theta, and little o notation to describe the amount of work done by an algorithm
+
+
+
+
+
+
+
+
+ Use recurrence relations to determine the time complexity of recursively defined algorithms
+
+
+
+
+
+
+
+
+ Solve elementary recurrence relations, e.g., using some form of a Master Theorem
+
+
+
+
+
+
+
+
+ Perform empirical studies to validate hypotheses about runtime stemming from mathematical analysis. Run algorithms on input of various sizes and compare performance
+
+
+
+
+
+
+
+
+ For each of the above strategies, identify a practical example to which it would apply
+
+
+
+
+
+
+
+
+ Have facility mapping pseudocode to implementation, implementing examples of algorithmic strategies from scratch, and applying them to specific problems
+
+
+
+
+
+
+
+
+ Use a greedy approach to solve an appropriate problem and determine if the greedy rule chosen leads to an optimal solution
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use a divide-and-conquer algorithm to solve an appropriate problem
+
+
+
+
+
+
+
+
+ Use recursive backtracking to solve a problem such as navigating a maze.
+
+
+
+
+
+
+
+
+ Use dynamic programming to solve an appropriate problem
+
+
+
+
+
+
+
+
+ Describe various heuristic problem-solving methods.
+
+
+
+
+
+
+
+
+ Use a heuristic approach to solve an appropriate problem
+
+
+
+
+
+
+
+
+ Describe the trade-offs between brute force and other strategies.
+
+
+
+
+
+
+
+
+ Implement basic numerical algorithms
+
+
+
+
+
+
+
+
+ Implement simple search algorithms and explain the differences in their time complexities
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Be able to implement common quadratic and O(N log N) sorting algorithms
+
+
+
+
+
+
+
+
+ Understand the implementation of hash tables, including collision avoidance and resolution
+
+
+
+
+
+
+
+
+ Discuss the runtime and memory efficiency of principal algorithms for sorting, searching, and hashing
+
+
+
+
+
+
+
+
+ Discuss factors other than computational efficiency that influence the choice of algorithms, such as programming time, maintainability, and the use of application-specific patterns in the input data
+
+
+
+
+
+
+
+
+ Solve problems using fundamental graph algorithms, including depth-first and breadth-first search
+
+
+
+
+
+
+
+
+ Demonstrate the ability to evaluate algorithms, to select from a range of possible options, to provide justification for that selection, and to implement the algorithm in a particular context
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Solve problems using graph algorithms, including single-source and all-pairs shortest paths, and at least one minimum spanning tree algorithm
+
+
+
+
+
+
+
+
+ Be able to implement a string-matching algorithm
+
+
+
+
+
+
+
+
+ Discuss the concept of finite state machines
+
+
+
+
+
+
+
+
+ Design a deterministic finite state machine to accept a specified language
+
+
+
+
+
+
+
+
+ Generate a regular expression to represent a specified language
+
+
+
+
+
+
+
+
+ Explain why the halting problem has no algorithmic solution
+
+
+
+
+
+
+
+
+ Design a context-free grammar to represent a specified language
+
+
+
+
+
+
+
+
+ Define the classes P and NP
+ Define the classes P and NP. (Also appears in ALBasic Automata, Computability, and Complexity)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Explain the significance of NP-completeness
+ Explain the significance of NP-completeness. (Also appears in ALBasic Automata, Computability, and cComplexity)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Define the classes P and NP. (Also appears in ALBasic Automata, Computability, and Complexity)
+
+
+
+
+
+
+
+
+ Define the class EXP
+
+
+ Provide examples of classic NP-complete problems.
+
+
+
+
+
+
+
+
+ Prove that a problem is NP-complete by reducing a classic known NP-complete problem to it.
+
+
+
+
+
+
+
+
+ Determine a languagequot;s place in the Chomsky hierarchy (regular, context-free, recursively enumerable).
+
+
+
+
+
+
+
+
+ Prove that a language is in a specified class and that it is not in the next lower class.
+
+
+
+
+
+
+
+
+ Convert among equivalently powerful notations for a language, including among DFAs, NFAs, and regular expressions, and between PDAs and CFGs.
+
+
+
+
+
+
+
+
+ Explain the Church-Turing thesis and its significance.
+
+
+
+
+
+
+
+
+ Explain Ricequot;s Theorem and its significance.
+
+
+
+
+
+
+
+
+ Provide examples of uncomputable functions
+
+
+
+
+
+
+
+
+ Prove that a problem is uncomputable by reducing a classic known uncomputable problem to it
+
+
+
+
+
+
+
+
+ Understand the mapping of real-world problems to algorithmic solutions (e.g., as graph problems, linear programs, etc.)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use advanced algorithmic techniques (e.g., randomization, approximation) to solve real problems.
+
+
+
+
+
+
+
+
+ Apply advanced analysis techniques (e.g., amortized, probabilistic, etc.) to algorithms
+
+
+ Describe the progression of computer technology components from vacuum tubes to VLSI, from mainframe computer architectures to the organization of warehouse-scale computers
+
+
+
+
+
+
+
+
+ Comprehend the trend of modern computer architectures towards multi-core and that parallelism is inherent in all hardware systems
+
+
+
+
+
+
+
+
+ Articulate that there are many equivalent representations of computer functionality, including logical expressions and gates, and be able to use mathematical expressions to describe the functions of simple combinational and sequential circuits
+
+
+
+
+
+
+
+
+ Design the basic building blocks of a computer: arithmetic-logic unit (gate-level), registers (gate-level), central processing unit (register transfer-level), memory (register transfer-level)
+
+
+
+
+
+
+
+
+ Use CAD tools for capture, synthesis, and simulation to evaluate simple building blocks (e.g., arithmetic- logic unit, registers, movement between registers) of a simple computer design
+
+
+
+
+
+
+
+
+ Evaluate the functional and timing diagram behavior of a simple processor implemented at the logic circuit level
+
+
+
+
+
+
+
+
+ Explain why everything is data, including instructions, in computers
+
+
+
+
+
+
+
+
+ Explain the reasons for using alternative formats to represent numerical data
+
+
+
+
+
+
+
+
+ Describe how negative integers are stored in sign-magnitude and twos-complement representations
+
+
+
+
+
+
+
+
+ Explain how fixed-length number representations affect accuracy and precision
+
+
+
+
+
+
+
+
+ Describe the internal representation of non-numeric data, such as characters, strings, records, and arrays
+
+
+
+
+
+
+
+
+ Convert numerical data from one format to another
+
+
+
+
+
+
+
+
+ Write simple programs at the assemblymachine level for string processing and manipulation
+
+
+
+
+
+
+
+
+ Explain the organization of the classical von Neumann machine and its major functional units
+
+
+
+
+
+
+
+
+ Describe how an instruction is executed in a classical von Neumann machine, with extensions for threads, multiprocessor synchronization, and SIMD execution
+
+
+
+
+
+
+
+
+ Describe instruction level parallelism and hazards, and how they are managed in typical processor pipelines
+
+
+
+
+
+
+
+
+ Summarize how instructions are represented at both the machine level and in the context of a symbolic assembler
+
+
+
+
+
+
+
+
+ Demonstrate how to map between high-level language patterns into assemblymachine language notations
+
+
+
+
+
+
+
+
+ Explain different instruction formats, such as addresses per instruction and variable length vs. fixed length formats
+
+
+
+
+
+
+
+
+ Explain how subroutine calls are handled at the assembly level
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Explain the basic concepts of interrupts and IO operations
+
+
+
+
+
+
+
+
+ Write simple assembly language program segments
+
+
+
+
+
+
+
+
+ Show how fundamental high-level programming constructs are implemented at the machine-language level
+
+
+
+
+
+
+
+
+ Identify the main types of memory technology
+
+
+
+
+
+
+
+
+ Explain the effect of memory latency on running time
+
+
+
+
+
+
+
+
+ Describe how the use of memory hierarchy (cache, virtual memory) is used to reduce the effective memory latency
+
+
+
+
+
+
+
+
+ Describe the principles of memory management
+
+
+
+
+
+
+
+
+ Explain the workings of a system with virtual memory management
+
+
+
+
+
+
+
+
+ Compute Average Memory Access Time under a variety of memory system configurations and workload assumptions
+
+
+
+
+
+
+
+
+ Explain how interrupts are used to implement IO control and data transfers
+
+
+
+
+
+
+
+
+ Identify various types of buses in a computer system
+
+
+
+
+
+
+
+
+ Describe data access from a magnetic disk drive
+
+
+
+
+
+
+
+
+ Compare common network organizations, such as ethernetbus, ring, switched vs. routed
+
+
+
+
+
+
+
+
+ Identify interfaces needed for multimedia support, from storage, through network, to memory and display
+
+
+
+
+
+
+
+
+ Describe the advantages and limitations of RAID architectures
+
+
+
+
+
+
+
+
+ Compare alternative implementation of datapaths
+
+
+
+
+
+
+
+
+ Discuss the concept of control points and the generation of control signals using hardwired or microprogrammed implementations
+
+
+
+
+
+
+
+
+ Explain basic instruction level parallelism using pipelining and the major hazards that may occur
+
+
+
+
+
+
+
+
+ Design and implement a complete processor, including datapath and control
+
+
+
+
+
+
+
+
+ Determine, for a given processor and memory system implementation, the average cycles per instruction
+
+
+
+
+
+
+
+
+ Discuss the concept of parallel processing beyond the classical von Neumann model
+
+
+
+
+
+
+
+
+ Describe alternative architectures such as SIMD and MIMD
+
+
+
+
+
+
+
+
+ Explain the concept of interconnection networks and characterize different approaches
+
+
+
+
+
+
+
+
+ Discuss the special concerns that multiprocessing systems present with respect to memory management and describe how these are addressed
+
+
+
+
+
+
+
+
+ Describe the differences between memory backplane, processor memory interconnect, and remote memory via networks
+
+
+
+
+
+
+
+
+ Describe superscalar architectures and their advantages
+
+
+
+
+
+
+
+
+ Explain the concept of branch prediction and its utility
+
+
+
+
+
+
+
+
+ Characterize the costs and benefits of prefetching
+
+
+
+
+
+
+
+
+ Explain speculative execution and identify the conditions that justify it
+
+
+
+
+
+
+
+
+ Discuss the performance advantages that multithreading offered in an architecture along with the factors that make it difficult to derive maximum benefits from this approach
+
+
+
+
+
+
+
+
+ Describe the relevance of scalability to performance
+
+
+
+
+
+
+
+
+ Explain the concept of modeling and the use of abstraction that allows the use of a machine to solve a problem
+
+
+
+
+
+
+
+
+ Explain the concept of simulation.
+
+
+
+
+
+
+
+
+ Describe the relationship between modeling and simulation, i.e., thinking of simulation as dynamic modeling
+
+
+
+
+
+
+
+
+ Articulate the use of a formal mathematical model of a situation in the validation of a simulation.
+
+
+
+
+
+
+
+
+ Differentiate among the different types of simulations.
+
+
+
+
+
+
+
+
+ Describe several approaches to validating models.
+
+
+
+
+
+
+
+
+ Explain and give examples of the benefits of simulation and modeling in a range of important application areas
+
+
+ Demonstrate the ability to apply the techniques of modeling and simulation to a range of problem areas.
+
+
+ Explain the constructs and concepts of a particular modeling approach.
+
+
+ Explain the difference between validation and verification of a model; demonstrate the difference with specific examples
+
+
+ Verify and validate the results of a simulation.
+
+
+ Evaluate a simulation, highlighting the benefits and the drawbacks.
+
+
+ Choose an appropriate modeling approach for a given problem or situation.
+
+
+ Compare results from different simulations of the same situation and explain any differences.
+
+
+ Infer the behavior of a system from the results of a simulation of the system.
+
+
+ Extend or adapt an existing model to a new situation.
+
+
+ Explain the characteristics and defining properties of algorithms and how they relate to machine processing
+
+
+ Analyze simple problem statements to identify relevant information and select appropriate processing to solve the problem
+
+
+ Identify or sketch a workflow for an existing computational process such as the creation of a graph based om experimental data
+
+
+ Describe the process of converting an algorithm to machine-executable code.
+
+
+ Summarize the phases of software development and compare several common lifecycle models.
+
+
+ Explain how data is represented in a machine. Compare representations of integers to floating point numbers. Describe underflow, overflow, round off, and truncation errors in data representations.
+
+
+ Apply standard numerical algorithms to solve ODEs and PDEs. Use computing systems to solve systems of equations
+
+
+ Describe the basic properties of bandwidth, latency, scalability and granularity.
+
+
+ Describe the levels of parallelism including task, data, and event parallelism.
+
+
+ Compare and contrast parallel programming paradigms recognizing the strengths and weaknesses of each.
+
+
+ Identify the issues impacting correctness and efficiency of a computation.
+
+
+ Design, code, test and debug programs for a parallel computation.
+
+
+ Compare common computer interface mechanisms with respect to ease-of-use, learnability, and cost.
+
+
+ Use standard APIs and tools to create visual displays of data, including graphs, charts, tables, and histograms
+
+
+ Describe several approaches to using a computer as a means for interacting with and processing data.
+
+
+ Extract useful information from a dataset.
+
+
+ Analyze and select visualization techniques for specific problems.
+
+
+ Describe issues related to scaling data analysis from small to large data sets.
+
+
+ Identify all of the data, information, and knowledge elements and related organizations, for a computational science application
+
+
+ Describe how to represent data and information for processing.
+
+
+ Describe typical user requirements regarding that data, information, and knowledge.
+
+
+ Select a suitable system or software implementation to manage data, information, and knowledge.
+
+
+ List and describe the reports, transactions, and other processing needed for a computational science application
+
+
+ Compare and contrast database management, information retrieval, and digital library systems with regard to handling typical computational science applications.
+
+
+ Explain with examples the basic terminology of functions, relations, and sets.
+
+
+
+
+
+
+
+
+ Perform the operations associated with sets, functions, and relations
+
+
+
+
+
+
+
+
+ Relate practical examples to the appropriate set, function, or relation model, and interpret the associated operations and terminology in context.
+
+
+
+
+
+
+
+
+ Convert logical statements from informal language to propositional and predicate logic expressions.
+
+
+
+
+
+
+
+
+ Apply formal methods of symbolic propositional and predicate logic, such as calculating validity of formulae and computing normal forms.
+
+
+
+
+
+
+
+
+ Use the rules of inference to construct proofs in propositional and predicate logic.
+
+
+
+
+
+
+
+
+ Describe how symbolic logic can be used to model real-life situations or applications, including those arising in computing contexts such as software analysis (e.g., program correctness), database queries, and algorithms
+
+
+
+
+
+
+
+
+ Apply formal logic proofs andor informal, but rigorous, logical reasoning to real problems, such as predicting the behavior of software or solving problems such as puzzles
+
+
+
+
+
+
+
+
+ Describe the strengths and limitations of propositional and predicate logic
+
+
+
+
+
+
+
+
+ Identify the proof technique used in a given proof.
+
+
+
+
+
+
+
+
+ Outline the basic structure of each proof technique described in this unit.
+
+
+
+
+
+
+
+
+ Apply each of the proof techniques correctly in the construction of a sound argument.
+
+
+
+
+
+
+
+
+ Determine which type of proof is best for a given problem.
+
+
+
+
+
+
+
+
+ Explain the relationship between weak and strong induction and give examples of the appropriate use of each
+
+
+
+
+
+
+
+
+ Apply counting arguments, including sum and product rules, inclusion-exclusion principle and arithmeticgeometric progressions.
+
+
+
+
+
+
+
+
+ Apply the pigeonhole principle in the context of a formal proof.
+
+
+
+
+
+
+
+
+ Compute permutations and combinations of a set, and interpret the meaning in the context of the particular application
+
+
+
+
+
+
+
+
+ Map real-world applications to appropriate counting formalisms, such as determining the number of ways to arrange people around a table, subject to constraints on the seating arrangement, or the number of ways to determine certain hands in cards (e.g., a full house).
+
+
+
+
+
+
+
+
+ Solve a variety of basic recurrence relations.
+
+
+
+
+
+
+
+
+ Analyze a problem to determine underlying recurrence relations.
+
+
+
+
+
+
+
+
+ Perform computations involving modular arithmetic.
+
+
+
+
+
+
+
+
+ Illustrate by example the basic terminology of graph theory, and some of the properties and special cases of each type of graphtree.
+
+
+
+
+
+
+
+
+ Demonstrate different traversal methods for trees and graphs, including pre, post, and in-order traversal of trees
+
+
+
+
+
+
+
+
+ Model a variety of real-world problems in computer science using appropriate forms of graphs and trees,such as representing a network topology or the organization of a hierarchical file system.
+
+
+
+
+
+
+
+
+ Show how concepts from graphs and trees appear in data structures, algorithms, proof techniques (structural induction), and counting.
+
+
+
+
+
+
+
+
+ Calculate probabilities of events and expectations of random variables for elementary problems such as games of chance
+
+
+
+
+
+
+
+
+ Differentiate between dependent and independent events.
+
+
+
+
+
+
+
+
+ Explain how events that are independent can be conditionally dependent (and vice-versa). Identify real- world examples of such cases.
+
+
+
+
+
+
+
+
+ Identify a case of the binomial distribution and compute a probability using that distribution.
+
+
+
+
+
+
+
+
+ Make a probabilistic inference in a real-world problem using Bayesquot; theorem to determine the probability of a hypothesis given evidence
+
+
+
+
+
+
+
+
+ Apply the tools of probability to solve problems such as the average case analysis of algorithms or analyzing hashing
+
+
+
+
+
+
+
+
+ Describe the basic process of human visual perception including the perception of continuous motion from a sequence of discrete frames (sometimes called flicker fusion), tricolor stimulus, depth cues, contrast sensitivity, and the limits of human visual acuity
+
+
+
+
+
+
+
+
+ Describe color models and their use in graphics display devices.
+
+
+
+
+
+
+
+
+ Differentiate between vector and raster rendering.
+
+
+
+
+
+
+
+
+ Introduce the algorithmic distinction between projecting light from surfaces forward to the screen (e.g., triangle rasterization and splatting) vs. tracing the path of light backwards (e.g., ray or beam tracing).
+
+
+
+
+
+
+
+
+ Identify common uses of computer graphics.
+
+
+
+
+
+
+
+
+ Model simple graphics images.
+
+
+
+
+
+
+
+
+ Create 2D or 3D images using a standard graphics API.
+
+
+
+
+
+
+
+
+ Describe the basic graphics pipeline and how forward and backward rendering factor in this.
+
+
+
+
+
+
+
+
+ Describe the differences between lossy and lossless image compression techniques, for example as reflected in common graphics image file formats such as JPG, PNG, and GIF
+
+
+
+
+
+
+
+
+ Apply a data compression algorithm such as run-length, Haar-wavelet, JPEG encoding, Huffman coding or Ziv-Lempel.
+
+
+
+
+
+
+
+
+ Apply double-buffering in the generation of a graphics application.
+
+
+
+
+
+
+
+
+ Discuss the light transport problem and its relation to numerical integration i.e., light is emitted, scatters around the scene, and is measured by the eye; the form is an integral equation without analytic solution, but we can approach it as numerical integration.
+
+
+ Obtain 2-dimensional and 3-dimensional points by applying affine transformations.
+
+
+ Apply 3-dimensional coordinate system and the changes required to extend 2D transformation operations to handle transformations in 3D.
+
+
+ Contrast forward and backward rendering.
+
+
+ Explain the concept and applications of texture mapping, sampling, and anti-aliasing.
+
+
+ Explain the ray tracing – rasterization duality for the visibility problem.
+
+
+ Implement simple procedures that perform transformation and clipping operations on simple 2-dimensional images
+
+
+ Implement a simple real-time renderer using a rasterization API (e.g., OpenGL) using vertex buffers and shaders
+
+
+ Compare and contrast the different rendering techniques.
+
+
+ Compute space requirements based on resolution and color coding.
+
+
+ Compute time requirements based on refresh rates, rasterization techniques.
+
+
+ Represent curves and surfaces using both implicit and parametric forms.
+
+
+ Create simple polyhedral models by surface tessellation.
+
+
+ Implement such algorithms as
+
+
+ Generate a mesh representation from an implicit surface.
+
+
+ Generate a fractal model or terrain using a procedural method.
+
+
+ Generate a mesh from data points acquired with a laser scanner.
+
+
+ Construct CSG models from simple primitives, such as cubes and quadric surfaces.
+
+
+ Contrast modeling approaches with respect to space and time complexity and quality of image.
+
+
+ Demonstrate how an algorithm estimates a solution to the rendering equation.
+
+
+ Prove the properties of a rendering algorithm, e.g., complete, consistent, andor unbiased.
+
+
+ Analyze the bandwidth and computation demands of a simple algorithm.
+
+
+ Implement a non-trivial shading algorithm (e.g., toon shading, cascaded shadow maps) under a rasterization API
+
+
+ Discuss how a particular artistic technique might be implemented in a renderer.
+
+
+ Explain how to recognize the graphics techniques used to create a particular image.
+
+
+ Implement any of the specified graphics techniques using a primitive graphics system at the individual pixel level
+
+
+ Implement a ray tracer for scenes using a simple (e.g., Phongquot;s) BRDF plus reflection and refraction.
+
+
+ Compute the location and orientation of model parts using an forward kinematic approach.
+
+
+ Compute the orientation of articulated parts of a model from a location and orientation using an inverse kinematic approach.
+
+
+ Describe the tradeoffs in different representations of rotations.
+
+
+ Implement the spline interpolation method for producing in-between positions and orientations.
+
+
+ Implement algorithms for physical modeling of particle dynamics using simple Newtonian mechanics, for example Witkin Kass, snakes and worms, symplectic Euler, StormerVerlet, or midpoint Euler methods
+
+
+ Describe the tradeoffs in different approaches to ODE integration for particle modeling.
+
+
+ Discuss the basic ideas behind some methods for fluid dynamics for modeling ballistic trajectories, for example for splashes, dust, fire, or smoke.
+
+
+ Use common animation software to construct simple organic forms using metaball and skeleton.
+
+
+ Describe the basic algorithms for scalar and vector visualization.
+
+
+ Describe the tradeoffs of algorithms in terms of accuracy and performance.
+
+
+ Propose a suitable visualization design for a particular combination of data characteristics and application tasks
+
+
+ Discuss the effectiveness of a given visualization for a particular task.
+
+
+ Design a process to evaluate the utility of a visualization algorithm or system.
+
+
+ Recognize a variety of applications of visualization including representations of scientific, medical, and mathematical data; flow visualization; and spatial analysis.
+
+
+ Discuss why human-centered software development is important
+
+
+
+
+
+
+
+
+ Summarize the basic precepts of psychological and social interaction
+
+
+
+
+
+
+
+
+ Develop and use a conceptual vocabulary for analyzing human interaction with software: affordance, conceptual model, feedback, and so forth
+
+
+ Define a user-centered design process that explicitly recognizes that the user is not like the developer or her acquaintances
+
+
+ Create and conduct a simple usability test for an existing software application
+
+
+
+
+
+
+
+
+ Create a simple application, together with help documentation, that supports a user interface
+
+
+
+
+
+
+
+
+ Conduct a quantitative evaluation and discussreport the results
+
+
+
+
+
+
+
+
+ Discuss at least one national or international user interface design standard
+
+
+ Understand there are common approaches to design problems, and be able to explain the importance of MVC to GUI programming
+
+
+
+
+
+
+
+
+ Create an application with a modern l user interface
+
+
+
+
+
+
+
+
+ Identify commonalities and differences in UIs across different platforms
+
+
+
+
+
+
+
+
+ Explain and use GUI programming concepts: event handling, constraint-based layout management, etc
+
+
+
+
+
+
+
+
+ Understand how user-centered design complements other software process models
+
+
+
+
+
+
+
+
+ Choose appropriate methods to support the development of a specific UI
+
+
+
+
+
+
+
+
+ Use a variety of techniques to evaluate a given UI
+
+
+
+
+
+
+
+
+ Use lo-fi prototyping techniques to gather, and report, user responses
+
+
+
+
+
+
+
+
+ Describe the constraints and benefits of different evaluative methods
+
+
+ Describe when non-mouse interfaces are appropriate
+
+
+
+
+
+
+
+
+ Discuss the advantages (and disadvantages) of non-mouse interfaces
+
+
+
+
+
+
+
+
+ Understand the interaction possibilities beyond mouse-and-pointer interfaces
+
+
+ Describe the difference between synchronous and asynchronous communication
+
+
+
+
+
+
+
+
+ Compare the HCI issues in individual interaction with group interaction
+
+
+ Discuss several issues of social concern raised by collaborative software
+
+
+ Discuss the HCI issues in software that embodies human intention
+
+
+ Explain basic statistical concepts and their areas of application
+
+
+
+
+
+
+
+
+ Extract and articulate the statistical arguments used in papers which report HCI results
+
+
+ Devise appropriate statistical tests for a given HCI problem
+
+
+
+
+
+
+
+
+ Explain the concepts of phishing and spear phishing, and how to recognize them
+
+
+
+
+
+
+
+
+ Explain the concept of identity management and its importance
+
+
+
+
+
+
+
+
+ Describe the issues of trust in interface design with an example of a high and low trust system
+
+
+
+
+
+
+
+
+ Design a user interface for a security mechanism
+
+
+
+
+
+
+
+
+ Detail the processes of design appropriate to specific design orientations
+
+
+
+
+
+
+
+
+ Apply a variety of design methods to a given problem
+
+
+
+
+
+
+
+
+ Understand HCI as a design-oriented discipline.
+
+
+ Describe the optical model realized by a computer graphics system to synthesize stereoscopic view
+
+
+
+
+
+
+
+
+ Describe the principles of different viewer tracking technologies.
+
+
+
+
+
+
+
+
+ Describe the differences between geometry- and image-based virtual reality.
+
+
+
+
+
+
+
+
+ Describe the issues of user action synchronization and data consistency in a networked environment
+
+
+
+
+
+
+
+
+ Determine the basic requirements on interface, hardware, and software configurations of a VR system for a specified application
+
+
+
+
+
+
+
+
+ To be aware of the range of possibilities for games engines, including their potential and their limitations
+
+
+ Describe the types of threats to data and information systems
+
+
+
+
+
+
+
+
+ Describe why processes and data need protection
+
+
+
+
+
+
+
+
+ Describe the context in which Confidentiality, Integrity, and Availability are important to given processes or data ?
+
+
+
+
+
+
+
+
+ Determine if the security controls provide sufficient security for the required level of Confidentiality, Integrity, andor Availability
+
+
+
+
+
+
+
+
+ What are significant national level laws affecting the obligation for the protection of data?
+
+
+
+
+
+
+
+
+ Describe how laws affecting privacy and dataIP protection differ based on country?
+
+
+
+
+
+
+
+
+ Describe the major vulnerabilities present in systems today.
+
+
+
+
+
+
+
+
+ Define the fundamental motivations for intentional malicious exploitation of vulnerabilities.
+
+
+ Define the defense mechanisms that can be used to detect or mitigate malicious activity in IT systems.
+
+
+
+
+
+
+
+
+ Define an incident.
+
+
+
+
+
+
+
+
+ Enumerate the roles required in incident response and the common steps after an incident has been declared
+
+
+
+
+
+
+
+
+ Describe the actions taken in response to the discovery of a given incident
+
+
+
+
+
+
+
+
+ Identify protocols used to enhance Internet communication, and choose the appropriate protocol for a particular
+
+
+
+
+
+
+
+
+ Discuss the difference between secret key and public key encryption.
+
+
+
+
+
+
+
+
+ Discuss the fundamental ideas of public-key cryptography.
+
+
+
+
+
+
+
+
+ Discuss the role of a certificate authority in public-key cryptography.
+
+
+
+
+
+
+
+
+ Discuss non-repudiation
+
+
+
+
+
+
+
+
+ Describe a digital signature
+
+
+
+
+
+
+
+
+ Describe how public key encryption is used to encrypt email traffic.
+
+
+
+
+
+
+
+
+ Generate and distribute a PGP key pair and use the PGP package to send an encrypted e-mail message.
+
+
+
+
+
+
+
+
+ Describe how public key encryption is used to secure HTTP traffic.
+
+
+
+
+
+
+
+
+ Describe the security risks present in networking.
+
+
+
+
+
+
+
+
+ Discuss the differences in Network Intrusion Detection and Network Intrusion Prevention.
+
+
+
+
+
+
+
+
+ Describe how the basic security implications of a hub and a switch.
+
+
+
+
+
+
+
+
+ Describe how a system can intercept traffic in a local subnet.
+
+
+
+
+
+
+
+
+ Describe different implementations for intrusion detection.
+
+
+
+
+
+
+
+
+ Identify a buffer overflow vulnerability in code
+
+
+
+
+
+
+
+
+ Correct a buffer overflow error in code
+
+
+
+
+
+
+
+
+ Describe the methods that can be used to alert that a system has a backdoor installed.
+
+
+
+
+
+
+
+
+ Describe the methods that can be used to identify a system is running processes not desired be the system owner
+
+
+
+
+
+
+
+
+ Analyze a port listing for unwanted TCPUDP listeners.
+
+
+
+
+
+
+
+
+ Describe the difference between non-routable and routable IP addresses.
+
+
+
+
+
+
+
+
+ List the class A, B, and C non-routable IP ranges.
+
+
+
+
+
+
+
+
+ Describe the difference between stateful and non-stateful firewalls.
+
+
+
+
+
+
+
+
+ Implement firewalls to prevent specific IPquot;s or ports from traversing the firewall.
+
+
+
+
+
+
+
+
+ Describe the different actions a firewall can take with a packet.
+
+
+
+
+
+
+
+
+ Summarize common authentication protocols.
+
+
+
+
+
+
+
+
+ Describe and discuss recent successful security attacks.
+
+
+
+
+
+
+
+
+ Summarize the strengths and weaknesses associated with different approaches to security.
+
+
+
+
+
+
+
+
+ Describe what a message digest is and how it is commonly used.
+
+
+
+
+
+
+
+
+ What is the purpose of Cryptography? [Knowledge]
+
+
+
+
+
+
+
+
+ What is plain text? [Knowledge]
+
+
+
+
+
+
+
+
+ What is cipher text? [Knowledge]
+
+
+
+
+
+
+
+
+ What are the two basic methods (ciphers) for transforming plain text in cipher text? [Knowledge]
+
+
+
+
+
+
+
+
+ Describe attacks against a specified cypher. [Knowledge]
+
+
+
+
+
+
+
+
+ Define the following terms: Cipher, Cryptanalysis, Cryptographic Algorithm, Cryptology. [Knowledge]
+
+
+
+
+
+
+
+
+ What is the Work Function of a given cryptographic algorithm? [Knowledge]
+
+
+
+
+
+
+
+
+ What is a One Time Pad (Vernam Cipher)? [Knowledge]
+
+
+
+
+
+
+
+
+ What is a Symmetric Key operation? [Knowledge]
+
+
+
+
+
+
+
+
+ What is an Asymmetric Key operation? [Knowledge]
+
+
+
+
+
+
+
+
+ For a given problem and environment weigh the tradeoffs between a Symmetric and Asymmetric key operation
+
+
+
+
+
+
+
+
+ What are common Symmetric Key algorithms?
+
+
+
+
+
+
+
+
+ Explain in general how a public key algorithm works.
+
+
+
+
+
+
+
+
+ How does key recovery work?
+
+
+
+
+
+
+
+
+ List 5 public key algorithms.
+
+
+
+
+
+
+
+
+ Describe the process in the Diffie-Hellman key exchange.
+
+
+
+
+
+
+
+
+ What is a message digest and list 4 common algorithms?
+
+
+
+
+
+
+
+
+ What is a digital signature and how is one created?
+
+
+
+
+
+
+
+
+ What the three components of a PKI?
+
+
+
+
+
+
+
+
+ List the ways a PKI infrastructure can be attacked.
+
+
+
+
+
+
+
+
+ How is risk determined?
+
+
+
+
+
+
+
+
+ What does it mean to manage risk?
+
+
+
+
+
+
+
+
+ What is the primary purpose of risk management?
+
+
+
+
+
+
+
+
+ Who can accept Risk?
+
+
+
+
+
+
+
+
+ What is the objective of Security Controls in security management?
+
+
+
+
+
+
+
+
+ With respect to a risk program, what is an Asset?
+
+
+
+
+
+
+
+
+ With respect to a risk program, what is a Threat?
+
+
+
+
+
+
+
+
+ With respect to a risk program, what is a Vulnerability?
+
+
+
+
+
+
+
+
+ With respect to a risk program, what is a Safeguard?
+
+
+
+
+
+
+
+
+ With respect to a risk program, what is the Exposure Factor (EF)?
+
+
+
+
+
+
+
+
+ What is the difference between Quantitative Risk Analysis and Qualitative Risk Analysis?
+
+
+
+
+
+
+
+
+ How does an organization determine what safeguards or controls to implement?
+
+
+
+
+
+
+
+
+ What is Risk Analysis (RA)?
+
+
+
+
+
+
+
+
+ Describe how data is classified in either (government or commercial)?
+
+
+
+
+
+
+
+
+ When are the factors used when determining the classification of a piece of information?
+
+
+
+
+
+
+
+
+ What are three ways to deal with Risk?
+
+
+
+
+
+
+
+
+ What is a security policy and why does an organization need a security policy?
+
+
+
+
+
+
+
+
+ Come up with an example of your own, which would be caused by missing security policies.
+
+
+
+
+
+
+
+
+ What are the basic things that need to be explained to every employee about a security policy? At what point in their employment? Why?
+
+
+
+
+
+
+
+
+ Say you have an e-mail server that processes sensitive emails from important people. What kind of things should be put into the security policy for the email server?
+
+
+
+
+
+
+
+
+ Read your institutionquot;s security plan and critique the plan.
+
+
+
+
+
+
+
+
+ Update your institutionquot;s security plan.
+
+
+
+
+
+
+
+
+ What is a Digital Investigation?
+
+
+
+
+
+
+
+
+ What systems in an IT infrastructure might have forensically recoverable data?
+
+
+
+
+
+
+
+
+ Who in an organization is authorized to permit the conduct of a forensics investigation?
+
+
+
+
+
+
+
+
+ What is the Rule of Evidence?
+
+
+
+
+
+
+
+
+ What is a Chain of Custody?
+
+
+
+
+
+
+
+
+ Conduct a data collection on a hard drive.
+
+
+
+
+
+
+
+
+ Validate the integrity of a digital forensics data set.
+
+
+
+
+
+
+
+
+ Determine if a digital investigation is sound.
+
+
+
+
+
+
+
+
+ Describe the file system structure for a given device (NTFA, MFS, iNode, HFS…)
+
+
+
+
+
+
+
+
+ Determine if a certain string of data exists on a hard drive.
+
+
+
+
+
+
+
+
+ Describe the capture of live data for a forensics investigation.
+
+
+
+
+
+
+
+
+ Capture and interpret network traffic.
+
+
+
+
+
+
+
+
+ Discuss identity management and its role in access control systems.
+
+
+
+
+
+
+
+
+ Determine what user was logged onto a given system at a given time.
+
+
+
+
+
+
+
+
+ Determine the submissability (from a legal perspective) of data.
+
+
+
+
+
+
+
+
+ Evaluate a system for the presence of malware.
+
+
+
+
+
+
+
+
+ Explain the need for software security and how software security is different from security features like access control or cryptography.
+
+
+
+
+
+
+
+
+ Understand common threats to web applications and common vulnerabilities written by developers.
+
+
+
+
+
+
+
+
+ Define least privilege.
+
+
+
+
+
+
+
+
+ Define Defense in Depth.
+
+
+
+
+
+
+
+
+ Define service isolation in the context of enterprise systems.
+
+
+
+
+
+
+
+
+ Architect an enterprise system using the concept of service isolation.
+
+
+
+
+
+
+
+
+ Describe the methods to provide for access control and what enterprise services must exist.
+
+
+
+
+
+
+
+
+ Discuss how user systems integrate into an enterprise environment.
+
+
+
+
+
+
+
+
+ Discuss the risks client systems pose to an enterprise environment.
+
+
+
+
+
+
+
+
+ Describe various methods to manage client systems.
+
+
+
+
+
+
+
+
+ Create a risk model of a web application, ranking and detailing the risks to the systemquot;s assets.
+
+
+
+
+
+
+
+
+ Construct, document, and analyze security requirements with abuse cases and constraints.
+
+
+
+
+
+
+
+
+ Apply secure design principles, such as least privilege, to the design of a web application.
+
+
+
+
+
+
+
+
+ Validate both the input and output of a web application.
+
+
+
+
+
+
+
+
+ Use cryptography appropriately, including SSL and certificate management.
+
+
+
+
+
+
+
+
+ Create a test plan and conduct thorough testing of web applications with appropriate software assistance.
+
+
+
+
+
+
+
+
+ Describe the Design Principles for Protection Mechanisms (Saltzer and Schroeder )
+
+
+
+
+
+
+
+
+ Describe the Principles for Software Security (Viega and McGraw)
+
+
+
+
+
+
+
+
+ Define Principles for a Secure Design (Morrie Gasser)
+
+
+
+
+
+
+
+
+ Compare the principles for software and systems in the context of a software development effort.
+
+
+
+
+
+
+
+
+ Discuss the benefits and drawbacks of open-source vs proprietary software and security
+
+
+
+
+
+
+
+
+ Integrate trustworthy development practices into an existing software development lifecycle
+
+
+
+
+
+
+
+
+ Integrate authenticating libraries, DLL, run-time
+
+
+
+
+
+
+
+
+ Identify a buffer overflow in a code sample
+
+
+
+
+
+
+
+
+ Describe the difference between static and dynamic analysis.
+
+
+
+
+
+
+
+
+ Conduct static analysis to determine the security posture of a given application.
+
+
+
+
+
+
+
+
+ Monitor the execution of a software (dynamic analysis) and discuss the observed process flows.
+
+
+
+
+
+
+
+
+ How is quality assurance conducted for software development?
+
+
+
+
+
+
+
+
+ Participate in a code review focused on finding security bugs using static analysis tools.
+
+
+
+
+
+
+
+
+ Where does patch management fit in a software development project?
+
+
+
+
+
+
+
+
+ Describe how humans gain access to information and data to support their needs
+
+
+
+
+
+
+
+
+ Compare and contrast information with data and knowledge
+
+
+
+
+
+
+
+
+ Demonstrate uses of explicitly stored metadataschema associated with data
+
+
+
+
+
+
+
+
+ Identify issues of data persistence to an organization
+
+
+
+
+
+
+
+
+ Explain uses of declarative queries
+
+
+
+
+
+
+
+
+ Give a declarative version for a navigational query
+
+
+
+
+
+
+
+
+ Describe several technical solutions to the problems related to information privacy, integrity, security, and preservation
+
+
+
+
+
+
+
+
+ Explain measures of efficiency (throughput, response time) and effectiveness (recall, precision)
+
+
+
+
+
+
+
+
+ Describe approaches that scale up to globally networked systems
+
+
+
+
+
+
+
+
+ Identify vulnerabilities and failure scenarios in common forms of information systems
+
+
+
+
+
+
+
+
+ Explain the characteristics that distinguish the database approach from the traditional approach of programming with data files
+
+
+
+
+
+
+
+
+ Cite the basic goals, functions, models, components, applications, and social impact of database systems
+
+
+
+
+
+
+
+
+ Describe the components of a database system and give examples of their use
+
+
+
+
+
+
+
+
+ Identify major DBMS functions and describe their role in a database system
+
+
+
+
+
+
+
+
+ Explain the concept of data independence and its importance in a database system
+
+
+
+
+
+
+
+
+ Use a declarative query language to elicit information from a database
+
+
+
+
+
+
+
+
+ Categorize data models based on the types of concepts that they provide to describe the database structure—that is, conceptual data model, physical data model, and representational data model
+
+
+ Describe the modeling concepts and notation of widely used modeling notation (e.g., ERD notation, and UML), including their use in data modeling
+
+
+
+
+
+
+
+
+ Define the fundamental terminology used in the relational data model
+
+
+
+
+
+
+
+
+ Describe the basic principles of the relational data model
+
+
+
+
+
+
+
+
+ Apply the modeling concepts and notation of the relational data model
+
+
+
+
+
+
+
+
+ Describe the main concepts of the OO model such as object identity, type constructors, encapsulation, inheritance, polymorphism, and versioning
+
+
+
+
+
+
+
+
+ Describe the differences between relational and semi-structured data models
+
+
+
+
+
+
+
+
+ Give a semi-structured equivalent (e.g., in DTD or XML Schema) for a given relational schema
+
+
+
+
+
+
+
+
+ Generate an index file for a collection of resources.
+
+
+ Explain the role of an inverted index in locating a document in a collection
+
+
+ Explain how stemming and stop words affect indexing
+
+
+ Identify appropriate indices for given relational schema and query set
+
+
+ Estimate time to retrieve information, when indices are used compared to when they are not used.
+
+
+ Prepare a relational schema from a conceptual model developed using the entity- relationship model
+
+
+ Explain and demonstrate the concepts of entity integrity constraint and referential integrity constraint (including definition of the concept of a foreign key).
+
+
+ Demonstrate use of the relational algebra operations from mathematical set theory (union, intersection, difference, and Cartesian product) and the relational algebra operations developed specifically for relational databases (select (restrict), project, join, and division).
+
+
+ Demonstrate queries in the relational algebra.
+
+
+ Demonstrate queries in the tuple relational calculus.
+
+
+ Determine the functional dependency between two or more attributes that are a subset of a relation.
+
+
+ Connect constraints expressed as primary key and foreign key, with functional dependencies
+
+
+ Compute the closure of a set of attributes under given functional dependencies
+
+
+ Evaluate a proposed decomposition, to say whether or not it has lossless-join and dependency-preservation
+
+
+ Describe what is meant by 1NF, 2NF, 3NF, and BCNF.
+
+
+ Identify whether a relation is in 1NF, 2NF, 3NF, or BCNF.
+
+
+ Normalize a 1NF relation into a set of 3NF (or BCNF) relations and denormalize a relational schema.
+
+
+ Explain the impact of normalization on the efficiency of database operations, especially query optimization.
+
+
+ Describe what is a multivalued dependency and what type of constraints it specifies.
+
+
+ Explain why 4NF is useful in schema design.
+
+
+ Create a relational database schema in SQL that incorporates key, entity integrity, and referential integrity constraints
+
+
+ Demonstrate data definition in SQL and retrieving information from a database using the SQL SELECT statement.
+
+
+ Evaluate a set of query processing strategies and select the optimal strategy.
+
+
+ Create a non-procedural query by filling in templates of relations to construct an example of the desired query result
+
+
+ Embed object-oriented queries into a stand-alone language such as C++ or Java (e.g., SELECT Col.Method() FROM Object).
+
+
+ Write a stored procedure that deals with parameters and has some control flow, to provide a given functionality
+
+
+ Create a transaction by embedding SQL into an application program.
+
+
+ Explain the concept of implicit commits.
+
+
+ Describe the issues specific to efficient transaction execution.
+
+
+ Explain when and why rollback is needed and how logging assures proper rollback.
+
+
+ Explain the effect of different isolation levels on the concurrency control mechanisms.
+
+
+ Choose the proper isolation level for implementing a specified transaction protocol.
+
+
+ Explain the techniques used for data fragmentation, replication, and allocation during the distributed database design process.
+
+
+ Evaluate simple strategies for executing a distributed query to select the strategy that minimizes the amount of data transfer.
+
+
+ Explain how the two-phase commit protocol is used to deal with committing a transaction that accesses databases stored on multiple nodes.
+
+
+ Describe distributed concurrency control based on the distinguished copy techniques and the voting method
+
+
+ Describe the three levels of software in the client-server model.
+
+
+ Explain the concepts of records, record types, and files, as well as the different techniques for placing file records on disk.
+
+
+ Give examples of the application of primary, secondary, and clustering indexes.
+
+
+ Distinguish between a non-dense index and a dense index.
+
+
+ Implement dynamic multilevel indexes using B-trees.
+
+
+ Explain the theory and application of internal and external hashing techniques.
+
+
+ Use hashing to facilitate dynamic file expansion.
+
+
+ Describe the relationships among hashing, compression, and efficient database searches.
+
+
+ Evaluate costs and benefits of various hashing schemes.
+
+
+ Explain how physical database design affects database transaction efficiency.
+
+
+ Compare and contrast different conceptions of data mining as evidenced in both research and application.
+
+
+ Explain the role of finding associations in commercial market basket data.
+
+
+ Characterize the kinds of patterns that can be discovered by association rule mining.
+
+
+ Describe how to extend a relational system to find patterns using association rules.
+
+
+ Evaluate methodological issues underlying the effective application of data mining.
+
+
+ Identify and characterize sources of noise, redundancy, and outliers in presented data.
+
+
+ Identify mechanisms (on-line aggregation, anytime behavior, interactive visualization) to close the loop in the data mining process.
+
+
+ Describe why the various close-the-loop processes improve the effectiveness of data mining.
+
+
+ Explain basic information storage and retrieval concepts.
+
+
+ Describe what issues are specific to efficient information retrieval.
+
+
+ Give applications of alternative search strategies and explain why the particular search strategy is appropriate for the application.
+
+
+ Perform Internet-based research.
+
+
+ Design and implement a small to medium size information storage and retrieval system, or digital library.
+
+
+ Describe some of the technical solutions to the problems related to archiving and preserving information in a digital library.
+
+
+ Describe Turing test and the Chinese Room thought experiment.
+
+
+
+
+
+
+
+
+ Differentiate between the concepts of optimal reasoningbehavior and human-like reasoningbehavior.
+
+
+
+
+
+
+
+
+ Describe a given problem domain using the characteristics of the environments in which intelligent systems must function
+
+
+
+
+
+
+
+
+ Formulate an efficient problem space for a problem expressed in natural language (e.g., English) in terms of initial and goal states, and operators
+
+
+
+
+
+
+
+
+ Describe the role of heuristics and describe the trade-offs among completeness, optimality, time complexity, and space complexity.
+
+
+
+
+
+
+
+
+ Describe the problem of combinatorial explosion of search space and its consequences.
+
+
+
+
+
+
+
+
+ Select and implement an appropriate uninformed search algorithm for a problem, and characterize its time and space complexities
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select and implement an appropriate informed search algorithm for a problem by designing the necessary heuristic evaluation function.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Evaluate whether a heuristic for a given problem is admissiblecan guarantee optimal solution.
+
+
+
+
+
+
+
+
+ Formulate a problem specified in natural language (e.g., English) as a constraint-satisfaction problem and implement it using a chronological backtracking algorithm or stochastic local search.
+
+
+
+
+
+
+
+
+ Compare and contrast basic search issues with game playing issues
+
+
+
+
+
+
+
+
+ Translate a natural language (e.g., English) sentence into predicate logic statement.
+
+
+
+
+
+
+
+
+ Convert a quantified logic statement into clause form.
+
+
+
+
+
+
+
+
+ Apply resolution to a set of logic statements to answer a query.
+
+
+
+
+
+
+
+
+ Apply Bayes theorem to determine conditional probabilities in a problem.
+
+
+
+
+
+
+
+
+ Identify examples of classification tasks, including the available input features and output to be predicted.
+
+
+
+
+
+
+
+
+ Explain the difference between inductive and deductive learning.
+
+
+
+
+
+
+
+
+ Apply the simple statistical learning algorithm such as Naive Bayesian Classifier to a classification task and measure the classifiers accuracy.
+
+
+
+
+
+
+
+
+ Design and implement a genetic algorithm solution to a problem.
+
+
+
+
+
+
+
+
+ Design and implement a simulated annealing schedule to avoid local minima in a problem.
+
+
+
+
+
+
+
+
+ Design and implement A*beam search to solve a problem.
+
+
+
+
+
+
+
+
+ Apply minimax search with alpha-beta pruning to prune search space in a two-player game.
+
+
+
+
+
+
+
+
+ Compare and contrast genetic algorithms with classic search techniques.
+
+
+
+
+
+
+
+
+ Compare and contrast various heuristic searches vis-a-vis applicability to a given problem.
+
+
+
+
+
+
+
+
+ Compare and contrast the most common models used for structured knowledge representation, highlighting their strengths and weaknesses.
+
+
+
+
+
+
+
+
+ Identify the components of non-monotonic reasoning and its usefulness as a representational mechanisms for belief systems.
+
+
+
+
+
+
+
+
+ Compare and contrast the basic techniques for representing uncertainty.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Compare and contrast the basic techniques for qualitative representation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Apply situation and event calculus to problems of action and change.
+
+
+
+
+
+
+
+
+ Explain the distinction between temporal and spatial reasoning, and how they interrelate.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Explain the difference between rule-based, case-based and model-based reasoning techniques
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Define the concept of a planning system and how they differ from classical search techniques.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Describe the differences between planning as search, operator-based planning, and propositional planning, providing examples of domains where each is most applicable.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Explain the distinction between monotonic and non-monotonic inference.
+
+
+
+
+
+
+
+
+ Apply Bayesquot; rule to determine the probability of a hypothesis given evidence.
+
+
+
+
+
+
+
+
+ Explain how conditional independence assertions allow for greater efficiency of probabilistic systems.
+
+
+
+
+
+
+
+
+ Identify examples of knowledge representations for reasoning under uncertainty.
+
+
+
+
+
+
+
+
+ State the complexity of exact inference. Identify methods for approximate inference.
+
+
+
+
+
+
+
+
+ Design and implement at least one knowledge representation for reasoning under uncertainty.
+
+
+
+
+
+
+
+
+ Describe the complexities of temporal probabilistic reasoning.
+
+
+
+
+
+
+
+
+ Explain the complexities of temporal probabilistic reasoning.
+
+
+
+
+
+
+
+
+ Design and implement an HMM as one example of a temporal probabilistic system.
+
+
+
+
+
+
+
+
+ Describe the relationship between preferences and utility functions.
+
+
+
+
+
+
+
+
+ Explain how utility functions and probabilistic reasoning can be combined to make rational decisions.
+
+
+
+
+
+
+
+
+ List the defining characteristics of an intelligent agent.
+
+
+
+
+
+
+
+
+ Characterize and contrast the standard agent architectures.
+
+
+
+
+
+
+
+
+ Describe the applications of agent theory to domains such as software agents, personal assistants, and believable agents.
+
+
+
+
+
+
+
+
+ Describe the primary paradigms used by learning agents.
+
+
+
+
+
+
+
+
+ Demonstrate using appropriate examples how multi-agent systems support agent interaction.
+
+
+
+
+
+
+
+
+ Define and contrast deterministic and stochastic grammars, providing examples to show the adequacy of each
+
+
+
+
+
+
+
+
+ Simulate, apply, or implement classic and stochastic algorithms for parsing natural language.
+
+
+
+
+
+
+
+
+ Identify the challenges of representing meaning.
+
+
+
+
+
+
+
+
+ List the advantages of using standard corpora. Identify examples of current corpora for a variety of NLP tasks
+
+
+
+
+
+
+
+
+ Identify techniques for information retrieval, language translation, and text classification.
+
+
+
+
+
+
+
+
+ Explain the differences among the three main styles of learning: supervised, reinforcement, and unsupervised.
+
+
+
+
+
+
+
+
+ Implement simple algorithms for supervised learning, reinforcement learning, and unsupervised learning.
+
+
+
+
+
+
+
+
+ Determine which of the three learning styles is appropriate to a particular problem domain.
+
+
+
+
+
+
+
+
+ Compare and contrast each of the following techniques, providing examples of when each strategy is superior: decision trees, neural networks, and belief networks.
+
+
+
+
+
+
+
+
+ Evaluate the performance of a simple learning system on a real-world dataset.
+
+
+
+
+
+
+
+
+ Characterize the state of the art in learning theory, including its achievements and its shortcomings.
+
+
+
+
+
+
+
+
+ Explain the problem of overfitting, along with techniques for detecting and managing the problem.
+
+
+
+
+
+
+
+
+ List capabilities and limitations of todays state-of-the-art robot systems, including their sensors and the crucial sensor processing that informs those systems.
+
+
+
+
+
+
+
+
+ Integrate sensors, actuators, and software into a robot designed to undertake some task.
+
+
+
+
+
+
+
+
+ Implement fundamental motion planning algorithms within a robot configuration space.
+
+
+
+
+
+
+
+
+ Characterize the uncertainties associated with common robot sensors and actuators; articulate strategies for mitigating these uncertainties
+
+
+
+
+
+
+
+
+ Describe at least one approach for coordinating the actions and sensing of several robots to accomplish a single task
+
+
+
+
+
+
+
+
+ Summarize the importance of image and object recognition in AI and indicate several significant applications of this technology
+
+
+
+
+
+
+
+
+ List at least three image-segmentation approaches, such as thresholding, edge-based and region-based algorithms, along with their defining characteristics, strengths, and weaknesses.
+
+
+
+
+
+
+
+
+ Implement 2d object recognition based on contour- andor region-based shape representations.
+
+
+
+
+
+
+
+
+ Distinguish the goals of sound-recognition, speech-recognition, and speaker-recognition and identify how the raw audio signal will be handled differently in each of these cases.
+
+
+
+
+
+
+
+
+ Provide at least two examples of a transformation of a data source from one sensory domain to another,e.g., tactile data interpreted as single-band 2d images.
+
+
+
+
+
+
+
+
+ Implement a feature-extraction algorithm on real data, e.g., an edge or corner detector for images or vectors of Fourier coefficients describing a short slice of audio signal.
+
+
+
+
+
+
+
+
+ Implement an algorithm combining features into higher-level percepts, e.g., a contour or polygon from visual primitives or phoneme hypotheses from an audio signal
+
+
+
+
+
+
+
+
+ Implement a classification algorithm that segments input percepts into output categories and quantitatively evaluates the resulting classification.
+
+
+
+
+
+
+
+
+ Evaluate the performance of the underlying feature-extraction, relative to at least one alternative possible approach (whether implemented or not) in its contribution to the classification task (8), above.
+
+
+
+
+
+
+
+
+ Describe at least three classification approaches, their prerequisites for applicability, their strengths, and their shortcomings.
+
+
+
+
+
+
+
+
+ Articulate the organization of the Internet
+
+
+
+
+
+
+
+
+ List and define the appropriate network terminology
+
+
+
+
+
+
+
+
+ Describe the layered structure of a typical networked architecture
+
+
+
+
+
+
+
+
+ Identify the different levels of complexity in a network (edges, core, etc.)
+
+
+
+
+
+
+
+
+ List the differences and the relations between names and addresses in a network
+
+
+
+
+
+
+
+
+ Define the principles behind DNS and HTTP
+
+
+
+
+
+
+
+
+ Be able to implement a simple client-server socket-based application
+
+
+
+
+
+
+
+
+ Describe the operation of reliable delivery protocols
+
+
+
+
+
+
+
+
+ List the factors that affect the performance of reliable delivery protocols
+
+
+
+
+
+
+
+
+ Design and implement a simple reliable protocol
+
+
+
+
+
+
+
+
+ Describe the organization of the network layer
+
+
+
+
+
+
+
+
+ Describe how packets are forwarded in an IP networks
+
+
+
+
+
+
+
+
+ List the scalability benefits of hierarchical addressing
+
+
+
+
+
+
+
+
+ List the major steps in solving the multiple access problem
+
+
+
+
+
+
+
+
+ Describe how frames are forwarded in an Ethernet network
+
+
+
+
+
+
+
+
+ Identify the differences between IP and Ethernet
+
+
+
+
+
+
+
+
+ Describe the interrelations between IP and Ethernet
+
+
+
+
+
+
+
+
+ Describe how resources can be allocated in a network
+
+
+
+
+
+
+
+
+ Describe the congestion problem in a large network
+
+
+
+
+
+
+
+
+ Compare and contrast the fixed and dynamic allocation techniques
+
+
+
+
+
+
+
+
+ Describe the organization of a wireless network
+
+
+
+
+
+
+
+
+ Describe how wireless networks support mobile users
+
+
+
+
+
+
+
+
+ Explain the objectives and functions of modern operating systems [Knowledge].
+
+
+
+
+
+
+
+
+ Analyze the tradeoffs inherent in operating system design [Application].
+
+
+
+
+
+
+
+
+ Describe the functions of a contemporary operating system with respect to convenience, efficiency, and the ability to evolve
+
+
+
+
+
+
+
+
+ Discuss networked, client-server, distributed operating systems and how they differ from single user operating systems
+
+
+
+
+
+
+
+
+ Identify potential threats to operating systems and the security features design to guard against them
+
+
+
+
+
+
+
+
+ Explain the concept of a logical layer
+
+
+
+
+
+
+
+
+ Explain the benefits of building abstract layers in hierarchical fashion
+
+
+
+
+
+
+
+
+ Defend the need for APIs and middleware
+
+
+
+
+
+
+
+
+ Describe how computing resources are used by application software and managed by system software
+
+
+
+
+
+
+
+
+ Contrast kernel and user mode in an operating system
+
+
+
+
+
+
+
+
+ Discuss the advantages and disadvantages of using interrupt processing
+
+
+
+
+
+
+
+
+ Explain the use of a device list and driver IO queue
+
+
+
+
+
+
+
+
+ Describe the need for concurrency within the framework of an operating system
+
+
+
+
+
+
+
+
+ Demonstrate the potential run-time problems arising from the concurrent operation of many separate tasks
+
+
+
+
+
+
+
+
+ Summarize the range of mechanisms that can be employed at the operating system level to realize concurrent systems and describe the benefits of each
+
+
+
+
+
+
+
+
+ Explain the different states that a task may pass through and the data structures needed to support the management of many tasks
+
+
+
+
+
+
+
+
+ Summarize techniques for achieving synchronization in an operating system (e.g., describe how to implement a semaphore using OS primitives)
+
+
+
+
+
+
+
+
+ Describe reasons for using interrupts, dispatching, and context switching to support concurrency in an operating system
+
+
+
+
+
+
+
+
+ Create state and transition diagrams for simple problem domains
+
+
+
+
+
+
+
+
+ Compare and contrast the common algorithms used for both preemptive and non-preemptive scheduling of tasks in operating systems, such as priority, performance comparison, and fair-share schemes
+
+
+
+
+
+
+
+
+ Describe relationships between scheduling algorithms and application domains
+
+
+
+
+
+
+
+
+ Discuss the types of processor scheduling such as short-term, medium-term, long-term, and IO
+
+
+
+
+
+
+
+
+ Describe the difference between processes and threads
+
+
+
+
+
+
+
+
+ Compare and contrast static and dynamic approaches to real-time scheduling
+
+
+
+
+
+
+
+
+ Discuss the need for preemption and deadline scheduling
+
+
+
+
+
+
+
+
+ Identify ways that the logic embodied in scheduling algorithms are applicable to other domains, such as disk IO, network scheduling, project scheduling, and problems beyond computing
+
+
+
+
+
+
+
+
+ Explain memory hierarchy and cost-performance trade-offs
+
+
+
+
+
+
+
+
+ Summarize the principles of virtual memory as applied to caching and paging
+
+
+
+
+
+
+
+
+ Evaluate the trade-offs in terms of memory size (main memory, cache memory, auxiliary memory) and processor speed
+
+
+
+
+
+
+
+
+ Defend the different ways of allocating memory to tasks, citing the relative merits of each
+
+
+
+
+
+
+
+
+ Describe the reason for and use of cache memory (performance and proximity, different dimension of how caches complicate isolation and VM abstraction)
+
+
+
+
+
+
+
+
+ Discuss the concept of thrashing, both in terms of the reasons it occurs and the techniques used to recognize and manage the problem
+
+
+
+
+
+
+
+
+ Summarize the features and limitations of an operating system used to provide protection and security (cross reference IASSecurity Architecture and Systems Administration)
+
+
+
+
+
+
+
+
+ Carry out simple system administration tasks according to a security policy, for example creating accounts, setting permissions, applying patches, and arranging for regular backups (cross reference IASSecurity Architecture and Systems Administration )
+
+
+
+
+
+
+
+
+ Explain the concept of virtual memory and how it is realized in hardware and software
+
+
+
+
+
+
+
+
+ Differentiate emulation and isolation
+
+
+
+
+
+
+
+
+ Evaluate virtualization trade-offs
+
+
+
+
+
+
+
+
+ Discuss hypervisors and the need for them in conjunction with different types of hypervisors
+
+
+
+
+
+
+
+
+ Explain the key difference between serial and parallel devices and identify the conditions in which each is appropriate
+
+
+
+
+
+
+
+
+ Identify the relationship between the physical hardware and the virtual devices maintained by the operating system
+
+
+
+
+
+
+
+
+ Explain buffering and describe strategies for implementing it
+
+
+
+
+
+
+
+
+ Differentiate the mechanisms used in interfacing a range of devices (including hand-held devices, networks, multimedia) to a computer and explain the implications of these for the design of an operating system
+
+
+
+
+
+
+
+
+ Describe the advantages and disadvantages of direct memory access and discuss the circumstances in which its use is warranted
+
+
+
+
+
+
+
+
+ Identify the requirements for failure recovery
+
+
+
+
+
+
+
+
+ Implement a simple device driver for a range of possible devices
+
+
+
+
+
+
+
+
+ Summarize the full range of considerations in the design of file systems
+
+
+
+
+
+
+
+
+ Compare and contrast different approaches to file organization, recognizing the strengths and weaknesses of each
+
+
+
+
+
+
+
+
+ Summarize how hardware developments have led to changes in the priorities for the design and the management of file systems
+
+
+
+
+
+
+
+
+ Summarize the use of journaling and how log-structured file systems enhance fault tolerance
+
+
+
+
+
+
+
+
+ Describe what makes a system a real-time system
+
+
+
+
+
+
+
+
+ Explain the presence of and describe the characteristics of latency in real-time systems
+
+
+
+
+
+
+
+
+ Summarize special concerns that real-time systems present and how these concerns are addressed
+
+
+
+
+
+
+
+
+ Explain the relevance of the terms fault tolerance, reliability, and availability
+
+
+
+
+
+
+
+
+ Outline the range of methods for implementing fault tolerance in an operating system
+
+
+
+
+
+
+
+
+ Explain how an operating system can continue functioning after a fault occurs
+
+
+
+
+
+
+
+
+ Describe the performance measurements used to determine how a system performs
+
+
+
+
+
+
+
+
+ Explain the main evaluation models used to evaluate a system
+
+
+
+
+
+
+
+
+ Describe how platform-based development differs from general purpose programming
+
+
+
+
+
+
+
+
+ List characteristics of platform languages
+
+
+
+
+
+
+
+
+ Write and execute a simple platform-based program
+
+
+
+
+
+
+
+
+ List the advantages and disadvantages of programming with platform constraints
+
+
+
+
+
+
+
+
+ Design and Implement a simple web application
+
+
+
+
+
+
+
+
+ Describe the constraints that the web puts on developers [
+
+
+
+
+
+
+
+
+ Compare and contrast web programming with general purpose programming
+
+
+
+
+
+
+
+
+ Describe the differences between Software-as-a-Service and traditional software products
+
+
+
+
+
+
+
+
+ Design and implement a mobile application for a given mobile platform.
+
+
+
+
+
+
+
+
+ Discuss the constraints that mobile platforms put on developers
+
+
+
+
+
+
+
+
+ Discuss the performance vs. power tradeoff
+
+
+
+
+
+
+
+
+ Compare and Contrast mobile programming with general purpose programming
+
+
+
+
+
+
+
+
+ Design and implement an industrial application on a given platform (Lego Mindstorms, Matlab, etc.)
+
+
+
+
+
+
+
+
+ Compare and contrast domain specific languages with general purpose programming languages.
+
+
+
+
+
+
+
+
+ Discuss the constraints that a given industrial platforms impose on developers
+
+
+
+
+
+
+
+
+ Design and Implement a simple application on a game platform.
+
+
+
+
+
+
+
+
+ Describe the constraints that game platforms impose on developers.
+
+
+
+
+
+
+
+
+ Compare and contrast game programming with general purpose programming
+
+
+
+
+
+
+
+
+ Distinguish using computational resources for a faster answer from managing efficient access to a shared resource
+
+
+
+
+
+
+
+
+ Distinguish multiple sufficient programming constructs for synchronization that may be inter-implementable but have complementary advantages
+
+
+
+
+
+
+
+
+ Distinguish data races from higher level races
+
+
+
+
+
+
+
+
+ Explain why synchronization is necessary in a specific parallel program
+
+
+
+
+
+
+
+
+ Write a correct and scalable parallel algorithm
+
+
+
+
+
+
+
+
+ Parallelize an algorithm by applying task-based decomposition
+
+
+
+
+
+
+
+
+ Parallelize an algorithm by applying data-parallel decomposition
+
+
+
+
+
+
+
+
+ Use mutual exclusion to avoid a given race condition
+
+
+
+
+
+
+
+
+ Give an example of an ordering of accesses among concurrent activities that is not sequentially consistent
+
+
+
+
+
+
+
+
+ Give an example of a scenario in which blocking message sends can deadlock
+
+
+
+
+
+
+
+
+ Explain when and why multicast or event-based messaging can be preferable to alternatives
+
+
+
+
+
+
+
+
+ Write a program that correctly terminates when all of a set of concurrent tasks have completed
+
+
+
+
+
+
+
+
+ Use a properly synchronized queue to buffer data passed among activities
+
+
+
+
+
+
+
+
+ Explain why checks for preconditions, and actions based on these checks, must share the same unit of atomicity to be effective
+
+
+
+
+
+
+
+
+ Write a test program that can reveal a concurrent programming error; for example, missing an update when two activities both try to increment a variable
+
+
+
+
+
+
+
+
+ Describe at least one design technique for avoiding liveness failures in programs using multiple locks or semaphores
+
+
+
+
+
+
+
+
+ Describe the relative merits of optimistic versus conservative concurrency control under different rates of contention among updates
+
+
+
+
+
+
+
+
+ Give an example of a scenario in which an attempted optimistic update may never complete
+
+
+
+
+
+
+
+
+ Use semaphores or condition variables to block threads until a necessary precondition holds
+
+
+
+
+
+
+
+
+ Define critical path, work, and span
+
+
+
+
+
+
+
+
+ Compute the work and span, and determine the critical path with respect to a parallel execution diagram
+
+
+
+
+
+
+
+
+ Define speed-up and explain the notion of an algorithmquot;s scalability in this regard
+
+
+
+
+
+
+
+
+ Identify independent tasks in a program that may be parallelized
+
+
+
+
+
+
+
+
+ Characterize features of a workload that allow or prevent it from being naturally parallelized
+
+
+
+
+
+
+
+
+ Decompose a problem (e.g., counting the number of occurrences of some word in a document) via map and reduce operations
+
+
+
+
+
+
+
+
+ Provide an example of a problem that fits the producer-consumer paradigm
+
+
+
+
+
+
+
+
+ Give examples of problems where pipelining would be an effective means of parallelization
+
+
+
+
+
+
+
+
+ Identify issues that arise in producer-consumer algorithms and mechanisms that may be used for addressing them
+
+
+
+
+
+
+
+
+ Describe the SMP architecture and note its key features
+
+
+
+
+
+
+
+
+ Characterize the kinds of tasks that are a natural match for SIMD machines
+
+
+
+
+
+
+
+
+ Explain the features of each classification in Flynnquot;s taxonomy
+
+
+
+
+
+
+
+
+ Explain the differences between shared and distributed memory
+
+
+
+
+
+
+
+
+ Describe the challenges in maintaining cache coherence
+
+
+
+
+
+
+
+
+ Describe the key features of different distributed system topologies
+
+
+
+
+
+
+
+
+ Calculate the implications of Amdahlquot;s law for a particular parallel algorithm
+
+
+
+
+
+
+
+
+ Describe how data distributionlayout can affect an algorithmquot;s communication costs
+
+
+
+
+
+
+
+
+ Detect and correct a load imbalance
+
+
+
+
+
+
+
+
+ Detect and correct an instance of false sharing
+
+
+
+
+
+
+
+
+ Explain the impact of scheduling on parallel performance
+
+
+
+
+
+
+
+
+ Explain performance impacts of data locality
+
+
+
+
+
+
+
+
+ Explain the impact and trade-off related to power usage on parallel performance
+
+
+
+
+
+
+
+
+ Distinguish network faults from other kinds of failures
+
+
+
+
+
+
+
+
+ Explain why synchronization constructs such as simple locks are not useful in the presence of distributed faults
+
+
+
+
+
+
+
+
+ Give examples of problems for which consensus algorithms such as leader election are required
+
+
+
+
+
+
+
+
+ Write a program that performs any required marshalling and conversion into message units, such as packets, to communicate interesting data between two hosts
+
+
+
+
+
+
+
+
+ Measure the observed throughput and response latency across hosts in a given network
+
+
+
+
+
+
+
+
+ Explain why no distributed system can be simultaneously consistent, available, and partition tolerant
+
+
+
+
+
+
+
+
+ Implement a simple server -- for example, a spell checking service
+
+
+
+
+
+
+
+
+ Explain the tradeoffs among overhead, scalability, and fault tolerance when choosing a stateful v. stateless design for a given service
+
+
+
+
+
+
+
+
+ Describe the scalability challenges associated with a service growing to accommodate many clients, as well as those associated with a service only transiently having many clients
+
+
+
+
+
+
+
+
+ Model a concurrent process using a formal model, such as pi-calculus
+
+
+
+
+
+
+
+
+ Explain the characteristics of a particular formal parallel model
+
+
+
+
+
+
+
+
+ Formally model a shared memory system to show if it is consistent
+
+
+
+
+
+
+
+
+ Use a model to show progress guarantees in a parallel algorithm
+
+
+
+
+
+
+
+
+ Use formal techniques to show that a parallel algorithm is correct with respect to a safety or liveness property
+
+
+
+
+
+
+
+
+ Decide if a specific execution is linearizable or not
+
+
+
+
+
+
+
+
+ Use subclassing to design simple class hierarchies that allow code to be reused for distinct subclasses
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use multiple encapsulation mechanisms, such as function closures, object-oriented interfaces, and support for abstract datatypes, in multiple programming languages
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Define and use iterators and other operations on aggregates using idioms most natural in multiple programming languages, including taking functions as arguments.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Write basic algorithms that avoid assigning to mutable state or considering object identity.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Write event handlers for use in reactive systems, such as GUIs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Explain the relationship between object-oriented inheritance (code-sharing and overriding) and subtyping (the idea of a subtype being usable in a context that expects the supertype)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Explain benefits and limitations of static typing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ For multiple programming languages, identify program properties checked statically and program properties checked dynamically. Use this knowledge when writing and debugging programs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Distinguish a language definition (what constructs mean) from a particular language implementation (compiler vs. interpreter, run-time representation of data objects, etc.).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Explain how programming language implementations typically organize memory into global data, text, heap, and stack sections and how features such as recursion and memory management map to this memory model.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reason about memory leaks, dangling-pointer dereferences, and the benefits and limitations of garbage collection
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Process some representation of code for some purpose, such as an interpreter, an expression optimizer, a documentation generator, etc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use formal grammars to specify the syntax of languages
+
+
+
+
+
+
+
+
+ Use declarative tools to generate parsers and scanners.
+
+
+
+
+
+
+
+
+ Identify key issues in syntax definitions: ambiguity, associativity, precedence.
+
+
+
+
+
+
+
+
+ Implement context-sensitive, source-level static analyses such as type-checkers or resolving identifiers to identify their binding occurrences
+
+
+
+
+
+
+
+
+ Identify all essential steps for automatically converting source code into assembly or other low-level languages
+
+
+
+
+
+
+
+
+ Generate the low-level code for calling functionsmethods in modern languages.
+
+
+
+
+
+
+
+
+ Discuss opportunities for optimization introduced by naive translation and approaches for achieving optimization
+
+
+
+
+
+
+
+
+ Compare the benefits of different memory-management schemes, using concepts such as fragmentation, locality, and memory overhead
+
+
+
+
+
+
+
+
+ Discuss benefits and limitations of automatic memory management.
+
+
+
+
+
+
+
+
+ Identify the services provided by modern language run-time systems.
+
+
+
+
+
+
+
+
+ Discuss advantages, disadvantages, and difficulties of dynamic recompilation.
+
+
+
+
+
+
+
+
+ Define useful static analyses in terms of a conceptual framework such as dataflow analysis. [Application]
+
+
+ Communicate why an analysis is correct (sound and terminating).
+
+
+
+
+
+
+
+
+ Distinguish may and must analyses.
+
+
+
+
+
+
+
+
+ Explain why potential aliasing limits sound program analysis and how alias analysis can help.
+
+
+
+
+
+
+
+
+ Use the results of a static analysis for program optimization andor partial program correctness.
+
+
+
+
+
+
+
+
+ Use various advanced programming constructs and idioms correctly.
+
+
+
+
+
+
+
+
+ Discuss how various advanced programming constructs aim to improve program structure, software quality, and programmer productivity
+
+
+
+
+
+
+
+
+ Discuss how various advanced programming constructs interact with the definition and implementation of other language features
+
+
+
+
+
+
+
+
+ Write correct concurrent programs using multiple programming models.
+
+
+
+
+
+
+
+
+ Explain why programming languages do not guarantee sequential consistency in the presence of data races and what programmers must do as a result.
+
+
+
+
+
+
+
+
+ Define a type system precisely and compositionally.
+
+
+
+
+
+
+
+
+ For various foundational type constructors, identify the values they describe and the invariants they enforce
+
+
+
+
+
+
+
+
+ Precisely specify the invariants preserved by a sound type system.
+
+
+
+
+
+
+
+
+ Give a formal semantics for a small language.
+
+
+
+
+
+
+
+
+ Use induction to prove properties of all (or a well-defined subset of) programs in a language.
+
+
+
+
+
+
+
+
+ Use language-based techniques to build a formal model of a software system.
+
+
+
+
+
+
+
+
+ Discuss the role of concepts such as orthogonality and well-chosen defaults in language design.
+
+
+
+
+
+
+
+
+ Use crisp and objective criteria for evaluating language-design decisions.
+
+
+
+
+
+
+
+
+ Use a logic language to implement conventional algorithms.
+
+
+
+
+
+
+
+
+ Use a logic language to implement algorithms employing implicit search using clauses and relations.
+
+
+
+
+
+
+
+
+ Discuss the importance of algorithms in the problem-solving process.
+
+
+
+
+
+
+
+
+ Discuss how a problem may be solved by multiple algorithms, each with different properties. [Knowledge]
+
+
+
+
+
+
+
+
+ Create algorithms for solving simple problems.
+
+
+
+
+
+
+
+
+ Use pseudocode or a programming language to implement, test, and debug algorithms for solving simple problems
+
+
+
+
+
+
+
+
+ Implement, test, and debug simple recursive functions and procedures.
+
+
+
+
+
+
+
+
+ Determine when a recursive solution is appropriate for a problem.
+
+
+
+
+
+
+
+
+ Implement a divide-and-conquer algorithm for solving a problem.
+
+
+
+
+
+
+
+
+ Apply the techniques of decomposition to break a program into smaller pieces.
+
+
+
+
+
+
+
+
+ Identify the data components and behaviors of multiple abstract data types.
+
+
+
+
+
+
+
+
+ Implement a coherent abstract data type, with loose coupling between components and behaviors.
+
+
+
+
+
+
+
+
+ Identify the relative strengths and weaknesses among multiple designs or implementations for a problem.
+
+
+
+
+
+
+
+
+ Analyze and explain the behavior of simple programs involving the fundamental programming constructs covered by this unit
+
+
+
+
+
+
+
+
+ Identify and describe uses of primitive data types.
+
+
+
+
+
+
+
+
+ Write programs that use each of the primitive data types.
+
+
+
+
+
+
+
+
+ Modify and expand short programs that use standard conditional and iterative control structures and functions
+
+
+
+
+
+
+
+
+ Design, implement, test, and debug a program that uses each of the following fundamental programming constructs: basic computation, simple IO, standard conditional and iterative structures, the definition of functions, and parameter passing.
+
+
+
+
+
+
+
+
+ Choose appropriate conditional and iteration constructs for a given programming task.
+
+
+
+
+
+
+
+
+ Describe the concept of recursion and give examples of its use.
+
+
+
+
+
+
+
+
+ Identify the base case and the general case of a recursively-defined problem.
+
+
+
+
+
+
+
+
+ Discuss the appropriate use of built-in data structures.
+
+
+
+
+
+
+
+
+ Describe common applications for each data structure in the topic list.
+
+
+
+
+
+
+
+
+ Compare alternative implementations of data structures with respect to performance.
+
+
+
+
+
+
+
+
+ Write programs that use each of the following data structures: arrays, strings, linked lists, stacks, queues, sets, and maps
+
+
+
+
+
+
+
+
+ Compare and contrast the costs and benefits of dynamic and static data structure implementations.
+
+
+
+
+
+
+
+
+ Choose the appropriate data structure for modeling a given problem
+
+
+
+
+
+
+
+
+ Explain why the creation of correct program components is important in the production of quality software.
+
+
+
+
+
+
+
+
+ Identify common coding errors that lead to insecure programs (e.g., buffer overflows, memory leaks, malicious code) and apply strategies for avoiding such errors.
+
+
+
+
+
+
+
+
+ Conduct a personal code review (focused on common coding errors) on a program component using a provided checklist
+
+
+
+
+
+
+
+
+ Contribute to a small-team code review focused on component correctness.
+
+
+
+
+
+
+
+
+ Describe how a contract can be used to specify the behavior of a program component.
+
+
+
+
+
+
+
+
+ Create a unit test plan for a medium-size code segment.
+
+
+
+
+
+
+
+
+ Apply a variety of strategies to the testing and debugging of simple programs.
+
+
+
+
+
+
+
+
+ Construct, execute and debug programs using a modern IDE (e.g., Visual Studio or Eclipse) and associated tools such as unit testing tools and visual debuggers.
+
+
+
+
+
+
+
+
+ Apply consistent documentation and program style standards that contribute to the readability and maintainability of software.
+
+
+
+
+
+
+
+
+ Describe how software can interact with and participate in various systems including information management, embedded, process control, and communications systems.
+
+
+
+
+
+
+
+
+ Differentiate among the phases of software development.
+
+
+
+
+
+
+
+
+ Explain the concept of a software life cycle and provide an example, illustrating its phases including the deliverables that are produced.
+
+
+
+
+
+
+
+
+ Describe how programming in the large differs from individual efforts with respect to understanding a large code base, code reading, understanding builds, and understanding context of changes.
+
+
+
+
+
+
+
+
+ Describe the difference between principles of the waterfall model and models using iterations.
+
+
+
+
+
+
+
+
+ Compare several common process models with respect to their value for development of particular classes of software systems taking into account issues such as requirement stability, size, and non-functional characteristics
+
+
+
+
+
+
+
+
+ Define software quality and describe the role of quality assurance activities in the software process.
+
+
+
+
+
+
+
+
+ Describe the intent and fundamental similarities among process improvement approaches
+
+
+
+
+
+
+
+
+ Compare several process improvement models such as CMM, CMMI, CQI, Plan-Do-Check-Act, or ISO9000.
+
+
+
+
+
+
+
+
+ Use a process improvement model such as PSP to assess a development effort and recommend approaches to improvement
+
+
+
+
+
+
+
+
+ Explain the role of process maturity models in process improvement.
+
+
+
+
+
+
+
+
+ Describe several process metrics for assessing and controlling a project.
+
+
+
+
+
+
+
+
+ Use project metrics to describe the current state of a project.
+
+
+
+
+
+
+
+
+ List several examples of software risks.
+
+
+
+
+
+
+
+
+ Describe the impact of risk in a software development life cycle.
+
+
+
+
+
+
+
+
+ Describe different categories of risk in software systems.
+
+
+
+
+
+
+
+
+ Describe the impact of risk tolerance on the software development process.
+
+
+
+
+
+
+
+
+ Identify risks and describe approaches to managing risk (avoidance, acceptance, transference, mitigation), and characterize the strengths and shortcomings of each
+
+
+
+
+
+
+
+
+ Explain how risk affects decisions in the software development process.
+
+
+
+
+
+
+
+
+ Identify behaviors that contribute to the effective functioning of a team.
+
+
+
+
+
+
+
+
+ Create and follow an agenda for a team meeting.
+
+
+
+
+
+
+
+
+ Identify and justify necessary roles in a software development team.
+
+
+
+
+
+
+
+
+ Understand the sources, hazards, and potential benefits of team conflict.
+
+
+
+
+
+
+
+
+ Apply a conflict resolution strategy in a team setting.
+
+
+
+
+
+
+
+
+ Use an ad hoc method to estimate software development effort (e.g., time) and compare to actual effort required
+
+
+
+
+
+
+
+
+ Identify security risks for a software system.
+
+
+
+
+
+
+
+
+ Demonstrate through involvement in a team project the central elements of team building and team management
+
+
+
+
+
+
+
+
+ Identify several possible team organizational structures and team decision-making processes.
+
+
+
+
+
+
+
+
+ Create a team by identifying appropriate roles and assigning roles to team members.
+
+
+
+
+
+
+
+
+ Assess and provide feedback to teams and individuals on their performance in a team setting.
+
+
+
+
+
+
+
+
+ Prepare a project plan for a software project that includes estimates of size and effort, a schedule, resource allocation, configuration control, change management, and project risk identification and management.
+
+
+
+
+
+
+
+
+ Track the progress of a project using appropriate project metrics.
+
+
+
+
+
+
+
+
+ Compare simple software size and cost estimation techniques.
+
+
+
+
+
+
+
+
+ Use a project management tool to assist in the assignment and tracking of tasks in a software development project
+
+
+
+
+
+
+
+
+ Demonstrate a systematic approach to the task of identifying hazards and risks in a particular situation.
+
+
+
+
+
+
+
+
+ Apply the basic principles of risk management in a variety of simple scenarios including a security situation
+
+
+
+
+
+
+
+
+ Conduct a costbenefit analysis for a risk mitigation approach.
+
+
+
+
+
+
+
+
+ Identify and analyze some of the risks for an entire system that arise from aspects other than the software.
+
+
+ Describe the difference between centralized and distributed software configuration management.
+
+
+
+
+
+
+
+
+ Identify configuration items and use a source code control tool in a small team-based project.
+
+
+
+
+
+
+
+
+ Describe the issues that are important in selecting a set of tools for the development of a particular software system, including tools for requirements tracking, design modeling, implementation, build automation, and testing
+
+
+
+
+
+
+
+
+ Demonstrate the capability to use software tools in support of the development of a software product of medium size
+
+
+
+
+
+
+
+
+ Describe the fundamental challenges of and common techniques used for requirements elicitation.
+
+
+
+
+
+
+
+
+ Interpret a given requirements model for a simple software system.
+
+
+
+
+
+
+
+
+ Conduct a review of a set of software requirements to determine the quality of the requirements with respect to the characteristics of good requirements.
+
+
+
+
+
+
+
+
+ List the key components of a use case or similar description of some behavior that is required for a system and discuss their role in the requirements engineering process.
+
+
+
+
+
+
+
+
+ List the key components of a class diagram or similar description of the data that a system is required to handle
+
+
+
+
+
+
+
+
+ Identify both functional and non-functional requirements in a given requirements specification for a software system
+
+
+
+
+
+
+
+
+ Apply key elements and common methods for elicitation and analysis to produce a set of software requirements for a medium-sized software system.
+
+
+
+
+
+
+
+
+ Use a common, non-formal method to model and specify (in the form of a requirements specification document) the requirements for a medium-size software system
+
+
+
+
+
+
+
+
+ Translate into natural language a software requirements specification (e.g., a software component contract) written in a formal specification language.
+
+
+
+
+
+
+
+
+ Create a prototype of a software system to mitigate risk in requirements.
+
+
+
+
+
+
+
+
+ Differentiate between forward and backward tracing and explain their roles in the requirements validation process
+
+
+
+
+
+
+
+
+ Articulate design principles including separation of concerns, information hiding, coupling and cohesion, and encapsulation
+
+
+
+
+
+
+
+
+ Use a design paradigm to design a simple software system, and explain how system design principles have been applied in this design
+
+
+
+
+
+
+
+
+ Construct models of the design of a simple software system that are appropriate for the paradigm used to design it
+
+
+
+
+
+
+
+
+ For the design of a simple software system within the context of a single design paradigm, describe the software architecture of that system
+
+
+
+
+
+
+
+
+ Within the context of a single design paradigm, describe one or more design patterns that could be applicable to the design of a simple software system.
+
+
+
+
+
+
+
+
+ Given a high-level design, identify the software architecture by differentiating among common software architectures such as 3-tier, pipe-and-filter, and client-server
+
+
+
+
+
+
+
+
+ For a simple system suitable for a given scenario, discuss and select an appropriate design paradigm
+
+
+
+
+
+
+
+
+ Create appropriate models for the structure and behavior of software products from their requirements specifications.
+
+
+
+
+
+
+
+
+ Explain the relationships between the requirements for a software product and the designed structure and behavior, in terms of the appropriate models and transformations of them.
+
+
+
+
+
+
+
+
+ Apply simple examples of patterns in a software design.
+
+
+
+
+
+
+
+
+ Investigate the impact of software architectures selection on the design of a simple system.
+
+
+ Select suitable components for use in the design of a software product.
+
+
+
+
+
+
+
+
+ Explain how suitable components might need to be adapted for use in the design of a software product.
+
+
+
+
+
+
+
+
+ Design a contract for a typical small software component for use in a given system
+
+
+
+
+
+
+
+
+ Discuss and select appropriate software architecture for a simple system suitable for a given scenario.
+
+
+
+
+
+
+
+
+ Apply models for internal and external qualities in designing software components to achieve an acceptable tradeoff between conflicting quality aspects
+
+
+
+
+
+
+
+
+ Analyze a software design from the perspective of a significant internal quality attribute.
+
+
+
+
+
+
+
+
+ Analyze a software design from the perspective of a significant external quality attribute.
+
+
+
+
+
+
+
+
+ Explain the role of objects in middleware systems and the relationship with components.
+
+
+
+
+
+
+
+
+ Apply component-oriented approaches to the design of a range of software, such as using components for concurrency and transactions, for reliable communication services, for database interaction including services for remote query and database management, or for secure communication and access.
+
+
+
+
+
+
+
+
+ Describe techniques, coding idioms and mechanisms for implementing designs to achieve desired properties such as reliability, efficiency, and robustness.
+
+
+
+
+
+
+
+
+ Build robust code using exception handling mechanisms.
+
+
+
+
+
+
+
+
+ Describe secure coding and defensive coding practices.
+
+
+
+
+
+
+
+
+ Select and use a defined coding standard in a small software project.
+
+
+
+
+
+
+
+
+ Compare and contrast integration strategies including top-down, bottom-up, and sandwich integration.
+
+
+
+
+
+
+
+
+ Rewrite a simple program to remove common vulnerabilities, such as buffer overflows, integer overflows and race conditions
+
+
+ State and apply the principles of least privilege and fail-safe defaults.
+
+
+ Write a simple library that performs some non-trivial task and will not terminate the calling program regardless of how it is called
+
+
+ Distinguish between program validation and verification.
+
+
+
+
+
+
+
+
+ Describe the role that tools can play in the validation of software.
+
+
+
+
+
+
+
+
+ Undertake, as part of a team activity, an inspection of a medium-size code segment.
+
+
+
+
+
+
+
+
+ Describe and distinguish among the different types and levels of testing (unit, integration, systems, and acceptance).
+
+
+
+
+
+
+
+
+ Use a defect tracking tool to manage software defects in a small software project
+
+
+
+
+
+
+
+
+ Describe the issues and approaches to testing distributed and parallel systems.
+
+
+
+
+
+
+
+
+ Create, evaluate, and implement a test plan for a medium-size code segment.
+
+
+
+
+
+
+
+
+ Compare static and dynamic approaches to verification.
+
+
+
+
+
+
+
+
+ Discuss the issues involving the testing of object-oriented software.
+
+
+
+
+
+
+
+
+ Describe techniques for the verification and validation of non-code artifacts.
+
+
+
+
+
+
+
+
+ Describe approaches for fault estimation.
+
+
+
+
+
+
+
+
+ Estimate the number of faults in a small software application based on fault density and fault seeding.
+
+
+
+
+
+
+
+
+ Conduct an inspection or review of software source code for a small or medium sized software project.
+
+
+
+
+
+
+
+
+ Identify the principal issues associated with software evolution and explain their impact on the software life cycle
+
+
+
+
+
+
+
+
+ Discuss the challenges of evolving systems in a changing environment.
+
+
+
+
+
+
+
+
+ Outline the process of regression testing and its role in release management
+
+
+
+
+
+
+
+
+ Discuss the advantages and disadvantages of software reuse.
+
+
+
+
+
+
+
+
+ Estimate the impact of a change request to an existing product of medium size.
+
+
+
+
+
+
+
+
+ Identify weaknesses in a given simple design, and removed them through refactoring
+
+
+
+
+
+
+
+
+ Describe the role formal specification and analysis techniques can play in the development of complex software and compare their use as validation and verification techniques with testing
+
+
+
+
+
+
+
+
+ Apply formal specification and analysis techniques to software designs and programs with low complexity.
+
+
+
+
+
+
+
+
+ Explain the potential benefits and drawbacks of using formal specification languages.
+
+
+
+
+
+
+
+
+ Create and evaluate program assertions for a variety of behaviors ranging from simple through complex.
+
+
+
+
+
+
+
+
+ Using a common formal specification language, formulate the specification of a simple software system and derive examples of test cases from the specification
+
+
+
+
+
+
+
+
+ Explain the problems that exist in achieving very high levels of reliability.
+
+
+
+
+
+
+
+
+ Describe how software reliability contributes to system reliability
+
+
+
+
+
+
+
+
+ List approaches to minimizing faults that can be applied at each stage of the software lifecycle.
+
+
+
+
+
+
+
+
+ Compare the characteristics of three different reliability modeling approaches.
+
+
+
+
+
+
+
+
+ Demonstrate the ability to apply multiple methods to develop reliability estimates for a software system.
+
+
+
+
+
+
+
+
+ Identify methods that will lead to the realization of a software architecture that achieves a specified reliability level of reliability
+
+
+
+
+
+
+
+
+ Identify ways to apply redundancy to achieve fault tolerance for a medium-sized application.
+
+
+
+
+
+
+
+
+ List commonly encountered patterns of how computations are organized
+
+
+
+
+
+
+
+
+ Describe the basic building blocks of computers and their role in the historical development of computer architecture
+
+
+
+
+
+
+
+
+ Articulate the differences between single thread vs. multiple thread, single server vs. multiple server models, motivated by real world examples (e.g., cooking recipes, lines for multiple teller machines, couple shopping for food, wash-dry-fold, etc.)
+
+
+
+
+
+
+
+
+ Articulate the concept of strong vs. weak scaling, i.e., how performance is affected by scale of problem vs. scale of resources to solve the problem. This can be motivated by the simple, real-world examples
+
+
+
+
+
+
+
+
+ Design and simulate a simple logic circuit using the fundamental building blocks of logic design
+
+
+
+
+
+
+
+
+ Write a simple sequential problem and a simple parallel version of the same program
+
+
+
+
+
+
+
+
+ Evaluate performance of simple sequential and parallel versions of a program with different problem sizes, and be able to describe the speed-ups achieved
+
+
+
+
+
+
+
+
+ Describe how computing systems are constructed of layers upon layers, based on separation of concerns, with well-defined interfaces, hiding details of low layers from the higher layers
+
+
+
+
+
+
+
+
+ Recognize that hardware, VM, OS, application are just additional layers of interpretationprocessing
+
+
+
+
+
+
+
+
+ Describe the mechanisms of how errors are detected, signaled back, and handled through the layers
+
+
+
+
+
+
+
+
+ Construct a simple program using methods of layering, error detection and recovery, and reflection of error status across layers
+
+
+
+
+
+
+
+
+ Find bugs in a layered program by using tools for program tracing, single stepping, and debugging
+
+
+
+
+
+
+
+
+ Describe computations as a system with a known set of configurations, and a byproduct of the computation is to transition from one unique configuration (state) to another (state)
+
+
+
+
+
+
+
+
+ Recognize the distinction between systems whose output is only a function of their input (Combinational) and those with memory or history (Sequential)
+
+
+
+
+
+
+
+
+ Describe a computer as a state machine that interprets machine instructions
+
+
+
+
+
+
+
+
+ Explain how a program or network protocol can also be expressed as a state machine, and that alternative representations for the same computation can exist
+
+
+
+
+
+
+
+
+ Develop state machine descriptions for simple problem statement solutions (e.g., traffic light sequencing, pattern recognizers)
+
+
+
+
+
+
+
+
+ Derive time-series behavior of a state machine from its state machine representation
+
+
+
+
+
+
+
+
+ For a given program, distinguish between its sequential and parallel execution, and the performance implications thereof
+
+
+
+
+
+
+
+
+ Demonstrate on an execution time line that parallel events and operations can take place simultaneously (i.e., at the same time). Explain how work can be performed in less elapsed time if this can be exploited
+
+
+
+
+
+
+
+
+ Explain other uses of parallelism, such as for reliabilityredundancy of execution
+
+
+
+
+
+
+
+
+ Define the differences between the concepts of Instruction Parallelism, Data Parallelism, Thread ParallelismMultitasking, TaskRequest Parallelism.
+
+
+ Write a simple parallel program in more than one paradigm so as to be able to compare and contrast ease of expression and performance in solving a given problem
+
+
+
+
+
+
+
+
+ Use performance tools to measure speed-up achieved by parallel programs in terms of both problem size and number of resources
+
+
+
+
+
+
+
+
+ Explain how the components of system architecture contribute to improving its performance
+
+
+
+
+
+
+
+
+ Describe Amdahlquot;s law and its implications for parallel system speed-up when limited by sequential portions, e.g., in processing pipelines
+
+
+
+
+
+
+
+
+ Benchmark a parallel program with different data sets in order to iteratively improve its performance
+
+
+
+
+
+
+
+
+ Use software tools to profile and measure program performance
+
+
+
+
+
+
+
+
+ Define how finite computer resources (e.g., processor share, memory, storage and network bandwidth) are managed by their careful allocation to existing entities
+
+
+
+
+
+
+
+
+ Describe the scheduling algorithms by which resources are allocated to competing entities, and the figures of merit by which these algorithms are evaluated, such as fairness
+
+
+
+
+
+
+
+
+ Implement simple scheduling algorithms
+
+
+
+
+
+
+
+
+ Measure figures of merit of different scheduler implementations
+
+
+
+
+
+
+
+
+ Explain the importance of locality in determining performance
+
+
+
+
+
+
+
+
+ Describe why things that are close in space take less time to access
+
+
+
+
+
+
+
+
+ Calculate average memory access time and describe the tradeoffs in memory hierarchy performance in terms of capacity, misshit rate, and access time
+
+
+
+
+
+
+
+
+ Explain why it is important to isolate and protect the execution of individual programs and environments that share common underlying resources, including the processor, memory, storage, and network access
+
+
+
+
+
+
+
+
+ Describe how the concept of indirection can create the illusion of a dedicated machine and its resources even when physically shared among multiple programs and environments
+
+
+
+
+
+
+
+
+ Measure the performance of two application instances running on separate virtual machines, and determine the effect of performance isolation
+
+
+
+
+
+
+
+
+ Explain the distinction between program errors, system errors, and hardware faults (e.g., bad memory) and exceptions (e.g., attempt to divide by zero)
+
+
+
+
+
+
+
+
+ Articulate the distinction between detecting, handling, and recovering from faults, and the methods for their implementation
+
+
+
+
+
+
+
+
+ Describe the role of error correcting codes in providing error checking and correction techniques in memories, storage, and networks
+
+
+
+
+
+
+
+
+ Apply simple algorithms for exploiting redundant information for the purposes of data correction
+
+
+
+
+
+
+
+
+ Compare different error detection and correction methods for their data overhead, implementation complexity, and relative execution time for encoding, detecting, and correcting errors
+
+
+
+
+
+
+
+
+ Describe positive and negative ways in which computer technology (networks, mobile computing, cloud computing) alters modes of social interaction at the personal level.
+
+
+
+
+
+
+
+
+ Identify developersquot; assumptions and values embedded in hardware and software design, especially as they pertain to usability for diverse populations including under-represented populations and the disabled.
+
+
+
+
+
+
+
+
+ Interpret the social context of a given design and its implementation.
+
+
+
+
+
+
+
+
+ Evaluate the efficacy of a given design and implementation using empirical data.
+
+
+
+
+
+
+
+
+ Investigate the implications of social media on individualism versus collectivism and culture.
+
+
+
+
+
+
+
+
+ Discuss how Internet access serves as a liberating force for people living under oppressive forms of government; explain how limits on Internet access are used as tools of political and social repression.
+
+
+
+
+
+
+
+
+ Analyze the pros and cons of reliance on computing in the implementation of democracy (e.g. delivery of social services, electronic voting)
+
+
+
+
+
+
+
+
+ Describe the impact of the under-representation of diverse populations in the computing profession (e.g., industry culture, product diversity).
+
+
+
+
+
+
+
+
+ Investigate the implications of context awareness in ubiquitous computing systems.
+
+
+
+
+
+
+
+
+ Evaluate stakeholder positions in a given situation.
+
+
+
+
+
+
+
+
+ Analyze basic logical fallacies in an argument.
+
+
+
+
+
+
+
+
+ Analyze an argument to identify premises and conclusion.
+
+
+
+
+
+
+
+
+ Illustrate the use of example and analogy in ethical argument.
+
+
+
+
+
+
+
+
+ Evaluate ethical tradeoffs in technical decisions.
+
+
+
+
+
+
+
+
+ Identify ethical issues that arise in software development and determine how to address them technically and ethically
+
+
+
+
+
+
+
+
+ Recognize the ethical responsibility of ensuring software correctness, reliability and safety.
+
+
+
+
+
+
+
+
+ Describe the mechanisms that typically exist for a professional to keep up-to-date.
+
+
+
+
+
+
+
+
+ Describe the strengths and weaknesses of relevant professional codes as expressions of professionalism and guides to decision-making
+
+
+
+
+
+
+
+
+ Analyze a global computing issue, observing the role of professionals and government officials in managing the problem
+
+
+
+
+
+
+
+
+ Evaluate the professional codes of ethics from the ACM, the IEEE Computer Society, and other organizations.
+
+
+
+
+
+
+
+
+ Describe ways in which professionals may contribute to public policy.
+
+
+
+
+
+
+
+
+ Describe the consequences of inappropriate professional behavior.
+
+
+
+
+
+
+
+
+ Identify progressive stages in a whistle-blowing incident.
+
+
+
+
+
+
+
+
+ Investigate forms of harassment and discrimination and avenues of assistance
+
+
+
+
+
+
+
+
+ Examine various forms of professional credentialing
+
+
+
+
+
+
+
+
+ Identify the social implications of ergonomic devices and the workplace environment to peoplequot;s health.
+
+
+
+
+
+
+
+
+ Develop a computer use policy with enforcement measures.
+
+
+
+
+
+
+
+
+ Describe issues associated with industries push to focus on time to market versus enforcing quality professional standards
+
+
+ Discuss the philosophical bases of intellectual property.
+
+
+
+
+
+
+
+
+ Discuss the rationale for the legal protection of intellectual property.
+
+
+
+
+
+
+
+
+ Describe legislation aimed at digital copyright infringements.
+
+
+
+
+
+
+
+
+ Critique legislation aimed at digital copyright infringements
+
+
+
+
+
+
+
+
+ Identify contemporary examples of intangible digital intellectual property
+
+
+
+
+
+
+
+
+ Justify uses of copyrighted materials.
+
+
+
+
+
+
+
+
+ Evaluate the ethical issues inherent in various plagiarism detection mechanisms.
+
+
+
+
+
+
+
+
+ Interpret the intent and implementation of software licensing.
+
+
+
+
+
+
+
+
+ Discuss the issues involved in securing software patents.
+
+
+
+
+
+
+
+
+ Characterize and contrast the concepts of copyright, patenting and trademarks.
+
+
+
+
+
+
+
+
+ Identify the goals of the open source movement.
+
+
+
+
+
+
+
+
+ Identify the global nature of software piracy.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Discuss the philosophical basis for the legal protection of personal privacy.
+
+
+
+
+
+
+
+
+ Evaluate solutions to privacy threats in transactional databases and data warehouses.
+
+
+
+
+
+
+
+
+ Recognize the fundamental role of data collection in the implementation of pervasive surveillance systems (e.g., RFID, face recognition, toll collection, mobile computing)
+
+
+
+
+
+
+
+
+ Recognize the ramifications of differential privacy.
+
+
+
+
+
+
+
+
+ Investigate the impact of technological solutions to privacy problems.
+
+
+
+
+
+
+
+
+ Critique the intent, potential value and implementation of various forms of privacy legislation.
+
+
+
+
+
+
+
+
+ Identify strategies to enable appropriate freedom of expression.
+
+
+
+
+
+
+
+
+ Write clear, concise, and accurate technical documents following well-defined standards for format and for including appropriate tables, figures, and references
+
+
+
+
+
+
+
+
+ Evaluate written technical documentation to detect problems of various kinds.
+
+
+
+
+
+
+
+
+ Develop and deliver a good quality formal presentation.
+
+
+
+
+
+
+
+
+ Plan interactions (e.g. virtual, face-to-face, shared documents) with others in which they are able to get their point across, and are also able to listen carefully and appreciate the points of others, even when they disagree, and are able to convey to others that they have heard.
+
+
+
+
+
+
+
+
+ Describe the strengths and weaknesses of various forms of communication (e.g. virtual, face-to-face, shared documents)
+
+
+
+
+
+
+
+
+ Examine appropriate measures used to communicate with stakeholders involved in a project.
+
+
+
+
+
+
+
+
+ Compare and contrast various collaboration tools.
+
+
+
+
+
+
+
+
+ Discuss ways to influence performance and results in cross-cultural teams.
+
+
+
+
+
+
+
+
+ Examine the tradeoffs and common sources of risk in software projects regarding technology, structureprocess, quality, people, market and financial.
+
+
+
+
+
+
+
+
+ Identify ways to be a sustainable practitioner
+
+
+
+
+
+
+
+
+ Illustrate global social and environmental impacts of computer use and disposal (e-waste)
+
+
+
+
+
+
+
+
+ Describe the environmental impacts of design choices within the field of computing that relate to algorithm design, operating system design, networking design, database design, etc.
+
+
+
+
+
+
+
+
+ Investigate the social and environmental impacts of new system designs through projects.
+
+
+
+
+
+
+
+
+ Identify guidelines for sustainable IT design or deployment
+
+
+
+
+
+
+
+
+ List the sustainable effects of telecommuting or web shopping
+
+
+
+
+
+
+
+
+ Investigate pervasive computing in areas such as smart energy systems, social networking, transportation, agriculture, supply-chain systems, environmental monitoring and citizen activism
+
+
+
+
+
+
+
+
+ Develop applications of computing and assess through research areas pertaining to environmental issues (e.g. energy, pollution, resource usage, recycling and reuse, food management, farming)
+
+
+
+
+
+
+
+
+ Identify significant continuing trends in the history of the computing field.
+
+
+
+
+
+
+
+
+ Identify the contributions of several pioneers in the computing field.
+
+
+
+
+
+
+
+
+ Discuss the historical context for several programming language paradigms.
+
+
+
+
+
+
+
+
+ Compare daily life before and after the advent of personal computers and the Internet.
+
+
+
+
+
+
+
+
+ Summarize the rationale for antimonopoly efforts.
+
+
+
+
+
+
+
+
+ Identify several ways in which the information technology industry is affected by shortages in the labor supply
+
+
+
+
+
+
+
+
+ Identify the evolution of pricing strategies for computing goods and services.
+
+
+
+
+
+
+
+
+ Discuss the benefits, the drawbacks and the implications of off-shoring and outsourcing.
+
+
+
+
+
+
+
+
+ Investigate and defend ways to address limitations on access to computing.
+
+
+
+
+
+
+
+
+ List examples of classic computer crimes and social engineering incidents with societal impact.
+
+
+
+
+
+
+
+
+ Identify laws that apply to computer crimes
+
+
+
+
+
+
+
+
+ Describe the motivation and ramifications of cyber terrorism and criminal hacking
+
+
+
+
+
+
+
+
+ Examine the ethical and legal issues surrounding the misuse of access and various breaches in security
+
+
+
+
+
+
+
+
+ Discuss the professionals role in security and the trade-offs involved.
+
+
+
+
+
+
+
+
+ Investigate measures that can be taken by both individuals and organizations including governments to prevent or mitigate the undesirable effects of computer crimes and identity theft
+
+
+
+
+
+
+
+
+ Write a company-wide security policy, which includes procedures for managing passwords and employee monitoring
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/models/courseManager.js b/models/courseManager.js
new file mode 100644
index 0000000..94234aa
--- /dev/null
+++ b/models/courseManager.js
@@ -0,0 +1,69 @@
+var Db = require('mongodb').Db;
+var Connection = require('mongodb').Connection;
+var Server = require('mongodb').Server;
+var BSON = require('mongodb').BSON;
+var ObjectID = require('mongodb').ObjectID;
+
+CourseManager = function(host, port, dbName) {
+ //console.log(host+port+dbName);
+ this.db= new Db(dbName, new Server(host, port), {auto_reconnect: true, safe: true});
+ this.db.open(function(err, client){
+ if(err){
+ console.log("Error!:"+err);
+ }else{
+ console.log("open OK");
+ }
+ });
+};
+
+CourseManager.prototype.getCollection= function(callback) {
+ this.db.collection('courses', function(error, coursesCollection) {
+ if( error ) callback(error);
+ else callback(null, coursesCollection);
+ });
+ };
+
+ CourseManager.prototype.findAll = function(callback) {
+ this.getCollection(function(error, coursesCollection) {
+ if( error ) callback(error);
+ else {
+ coursesCollection.find().toArray(function(error, results) {
+ if( error ) callback(error);
+ else callback(null, results);
+ });
+ }
+ });
+ };
+
+
+ CourseManager.prototype.findById = function(id, callback) {
+ this.getCollection(function(error, coursesCollection) {
+ if( error ) callback(error);
+ else {
+ coursesCollection.findOne({_id: coursesCollection.db.bson_serializer.ObjectID.createFromHexString(id)}, function(error, result) {
+ if( error ) callback(error);
+ else callback(null, result);
+ });
+ }
+ });
+ };
+
+ CourseManager.prototype.save = function(courses, callback) {
+ this.getCollection(function(error, coursesCollection) {
+ if( error ) callback(error);
+ else {
+ if( typeof(courses.length)=="undefined")
+ courses = [courses];
+ coursesCollection.insert(courses, function(err) {
+ if(err) console.log("ERROR:"+err);
+ callback(null, courses);
+ });
+ }
+ });
+ };
+
+ CourseManager.prototype.close = function(){
+ this.db.close();
+ }
+
+ exports.CourseManager = CourseManager;
\ No newline at end of file
diff --git a/node_modules/mongodb/.travis.yml b/node_modules/mongodb/.travis.yml
new file mode 100644
index 0000000..0140117
--- /dev/null
+++ b/node_modules/mongodb/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+ - 0.6
+ - 0.8
+ - 0.10 # development version of 0.8, may be unstable
\ No newline at end of file
diff --git a/node_modules/mongodb/CONTRIBUTING.md b/node_modules/mongodb/CONTRIBUTING.md
new file mode 100644
index 0000000..2a1c52e
--- /dev/null
+++ b/node_modules/mongodb/CONTRIBUTING.md
@@ -0,0 +1,23 @@
+## Contributing to the driver
+
+### Bugfixes
+
+- Before starting to write code, look for existing [tickets](https://github.com/mongodb/node-mongodb-native/issues) or [create one](https://github.com/mongodb/node-mongodb-native/issues/new) for your specific issue. That way you avoid working on something that might not be of interest or that has been addressed already in a different branch.
+- Fork the [repo](https://github.com/mongodb/node-mongodb-native) _or_ for small documentation changes, navigate to the source on github and click the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button.
+- Follow the general coding style of the rest of the project:
+ - 2 space tabs
+ - no trailing whitespace
+ - comma last
+ - inline documentation for new methods, class members, etc
+ - 0 space between conditionals/functions, and their parenthesis and curly braces
+ - `if(..) {`
+ - `for(..) {`
+ - `while(..) {`
+ - `function(err) {`
+- Write tests and make sure they pass (execute `make test` from the cmd line to run the test suite).
+
+### Documentation
+
+To contribute to the [API documentation](http://mongodb.github.com/node-mongodb-native/) just make your changes to the inline documentation of the appropriate [source code](https://github.com/mongodb/node-mongodb-native/tree/master/docs) in the master branch and submit a [pull request](https://help.github.com/articles/using-pull-requests/). You might also use the github [Edit](https://github.com/blog/844-forking-with-the-edit-button) button.
+
+If you'd like to preview your documentation changes, first commit your changes to your local master branch, then execute `make generate_docs`. Make sure you have the python documentation framework sphinx installed `easy_install sphinx`. The docs are generated under `docs/build'. If all looks good, submit a [pull request](https://help.github.com/articles/using-pull-requests/) to the master branch with your changes.
\ No newline at end of file
diff --git a/node_modules/mongodb/Makefile b/node_modules/mongodb/Makefile
new file mode 100644
index 0000000..59d2bfe
--- /dev/null
+++ b/node_modules/mongodb/Makefile
@@ -0,0 +1,28 @@
+NODE = node
+NPM = npm
+NODEUNIT = node_modules/nodeunit/bin/nodeunit
+DOX = node_modules/dox/bin/dox
+name = all
+
+total: build_native
+
+test_functional:
+ node test/runner.js -t functional
+
+test_ssl:
+ node test/runner.js -t ssl
+
+test_replicaset:
+ node test/runner.js -t replicaset
+
+test_sharded:
+ node test/runner.js -t sharded
+
+test_auth:
+ node test/runner.js -t auth
+
+generate_docs:
+ $(NODE) dev/tools/build-docs.js
+ make --directory=./docs/sphinx-docs --file=Makefile html
+
+.PHONY: total
diff --git a/node_modules/mongodb/Readme.md b/node_modules/mongodb/Readme.md
new file mode 100644
index 0000000..306fde7
--- /dev/null
+++ b/node_modules/mongodb/Readme.md
@@ -0,0 +1,442 @@
+Up to date documentation
+========================
+
+[Documentation](http://mongodb.github.com/node-mongodb-native/)
+
+Install
+=======
+
+To install the most recent release from npm, run:
+
+ npm install mongodb
+
+That may give you a warning telling you that bugs['web'] should be bugs['url'], it would be safe to ignore it (this has been fixed in the development version)
+
+To install the latest from the repository, run::
+
+ npm install path/to/node-mongodb-native
+
+Community
+=========
+Check out the google group [node-mongodb-native](http://groups.google.com/group/node-mongodb-native) for questions/answers from users of the driver.
+
+Live Examples
+============
+
+
+Introduction
+============
+
+This is a node.js driver for MongoDB. It's a port (or close to a port) of the library for ruby at http://github.com/mongodb/mongo-ruby-driver/.
+
+A simple example of inserting a document.
+
+```javascript
+ var client = new Db('test', new Server("127.0.0.1", 27017, {}), {w: 1}),
+ test = function (err, collection) {
+ collection.insert({a:2}, function(err, docs) {
+
+ collection.count(function(err, count) {
+ test.assertEquals(1, count);
+ });
+
+ // Locate all the entries using find
+ collection.find().toArray(function(err, results) {
+ test.assertEquals(1, results.length);
+ test.assertTrue(results[0].a === 2);
+
+ // Let's close the db
+ client.close();
+ });
+ });
+ };
+
+ client.open(function(err, p_client) {
+ client.collection('test_insert', test);
+ });
+```
+
+Data types
+==========
+
+To store and retrieve the non-JSON MongoDb primitives ([ObjectID](http://www.mongodb.org/display/DOCS/Object+IDs), Long, Binary, [Timestamp](http://www.mongodb.org/display/DOCS/Timestamp+data+type), [DBRef](http://www.mongodb.org/display/DOCS/Database+References#DatabaseReferences-DBRef), Code).
+
+In particular, every document has a unique `_id` which can be almost any type, and by default a 12-byte ObjectID is created. ObjectIDs can be represented as 24-digit hexadecimal strings, but you must convert the string back into an ObjectID before you can use it in the database. For example:
+
+```javascript
+ // Get the objectID type
+ var ObjectID = require('mongodb').ObjectID;
+
+ var idString = '4e4e1638c85e808431000003';
+ collection.findOne({_id: new ObjectID(idString)}, console.log) // ok
+ collection.findOne({_id: idString}, console.log) // wrong! callback gets undefined
+```
+
+Here are the constructors the non-Javascript BSON primitive types:
+
+```javascript
+ // Fetch the library
+ var mongo = require('mongodb');
+ // Create new instances of BSON types
+ new mongo.Long(numberString)
+ new mongo.ObjectID(hexString)
+ new mongo.Timestamp() // the actual unique number is generated on insert.
+ new mongo.DBRef(collectionName, id, dbName)
+ new mongo.Binary(buffer) // takes a string or Buffer
+ new mongo.Code(code, [context])
+ new mongo.Symbol(string)
+ new mongo.MinKey()
+ new mongo.MaxKey()
+ new mongo.Double(number) // Force double storage
+```
+
+The C/C++ bson parser/serializer
+--------------------------------
+
+If you are running a version of this library has the C/C++ parser compiled, to enable the driver to use the C/C++ bson parser pass it the option native_parser:true like below
+
+```javascript
+ // using native_parser:
+ var client = new Db('integration_tests_20',
+ new Server("127.0.0.1", 27017),
+ {native_parser:true});
+```
+
+The C++ parser uses the js objects both for serialization and deserialization.
+
+GitHub information
+==================
+
+The source code is available at http://github.com/mongodb/node-mongodb-native.
+You can either clone the repository or download a tarball of the latest release.
+
+Once you have the source you can test the driver by running
+
+ $ make test
+
+in the main directory. You will need to have a mongo instance running on localhost for the integration tests to pass.
+
+Examples
+========
+
+For examples look in the examples/ directory. You can execute the examples using node.
+
+ $ cd examples
+ $ node queries.js
+
+GridStore
+=========
+
+The GridStore class allows for storage of binary files in mongoDB using the mongoDB defined files and chunks collection definition.
+
+For more information have a look at [Gridstore](https://github.com/mongodb/node-mongodb-native/blob/master/docs/gridfs.md)
+
+Replicasets
+===========
+For more information about how to connect to a replicaset have a look at [Replicasets](https://github.com/mongodb/node-mongodb-native/blob/master/docs/replicaset.md)
+
+Primary Key Factories
+---------------------
+
+Defining your own primary key factory allows you to generate your own series of id's
+(this could f.ex be to use something like ISBN numbers). The generated the id needs to be a 12 byte long "string".
+
+Simple example below
+
+```javascript
+ // Custom factory (need to provide a 12 byte array);
+ CustomPKFactory = function() {}
+ CustomPKFactory.prototype = new Object();
+ CustomPKFactory.createPk = function() {
+ return new ObjectID("aaaaaaaaaaaa");
+ }
+
+ var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}), {'pk':CustomPKFactory});
+ p_client.open(function(err, p_client) {
+ p_client.dropDatabase(function(err, done) {
+ p_client.createCollection('test_custom_key', function(err, collection) {
+ collection.insert({'a':1}, function(err, docs) {
+ collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) {
+ cursor.toArray(function(err, items) {
+ test.assertEquals(1, items.length);
+
+ // Let's close the db
+ p_client.close();
+ });
+ });
+ });
+ });
+ });
+ });
+```
+
+Strict mode
+-----------
+
+Each database has an optional strict mode. If it is set then asking for a collection
+that does not exist will return an Error object in the callback. Similarly if you
+attempt to create a collection that already exists. Strict is provided for convenience.
+
+```javascript
+ var error_client = new Db('integration_tests_', new Server("127.0.0.1", 27017, {auto_reconnect: false}), {strict:true});
+ test.assertEquals(true, error_client.strict);
+
+ error_client.open(function(err, error_client) {
+ error_client.collection('does-not-exist', function(err, collection) {
+ test.assertTrue(err instanceof Error);
+ test.assertEquals("Collection does-not-exist does not exist. Currently in strict mode.", err.message);
+ });
+
+ error_client.createCollection('test_strict_access_collection', function(err, collection) {
+ error_client.collection('test_strict_access_collection', function(err, collection) {
+ test.assertTrue(collection instanceof Collection);
+ // Let's close the db
+ error_client.close();
+ });
+ });
+ });
+```
+
+Documentation
+=============
+
+If this document doesn't answer your questions, see the source of
+[Collection](https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/collection.js)
+or [Cursor](https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/cursor.js),
+or the documentation at MongoDB for query and update formats.
+
+Find
+----
+
+The find method is actually a factory method to create
+Cursor objects. A Cursor lazily uses the connection the first time
+you call `nextObject`, `each`, or `toArray`.
+
+The basic operation on a cursor is the `nextObject` method
+that fetches the next matching document from the database. The convenience
+methods `each` and `toArray` call `nextObject` until the cursor is exhausted.
+
+Signatures:
+
+```javascript
+ var cursor = collection.find(query, [fields], options);
+ cursor.sort(fields).limit(n).skip(m).
+
+ cursor.nextObject(function(err, doc) {});
+ cursor.each(function(err, doc) {});
+ cursor.toArray(function(err, docs) {});
+
+ cursor.rewind() // reset the cursor to its initial state.
+```
+
+Useful chainable methods of cursor. These can optionally be options of `find` instead of method calls:
+
+* `.limit(n).skip(m)` to control paging.
+* `.sort(fields)` Order by the given fields. There are several equivalent syntaxes:
+ * `.sort({field1: -1, field2: 1})` descending by field1, then ascending by field2.
+ * `.sort([['field1', 'desc'], ['field2', 'asc']])` same as above
+ * `.sort([['field1', 'desc'], 'field2'])` same as above
+ * `.sort('field1')` ascending by field1
+
+Other options of `find`:
+
+* `fields` the fields to fetch (to avoid transferring the entire document)
+* `tailable` if true, makes the cursor [tailable](http://www.mongodb.org/display/DOCS/Tailable+Cursors).
+* `batchSize` The number of the subset of results to request the database
+to return for every request. This should initially be greater than 1 otherwise
+the database will automatically close the cursor. The batch size can be set to 1
+with `batchSize(n, function(err){})` after performing the initial query to the database.
+* `hint` See [Optimization: hint](http://www.mongodb.org/display/DOCS/Optimization#Optimization-Hint).
+* `explain` turns this into an explain query. You can also call
+`explain()` on any cursor to fetch the explanation.
+* `snapshot` prevents documents that are updated while the query is active
+from being returned multiple times. See more
+[details about query snapshots](http://www.mongodb.org/display/DOCS/How+to+do+Snapshotted+Queries+in+the+Mongo+Database).
+* `timeout` if false, asks MongoDb not to time out this cursor after an
+inactivity period.
+
+
+For information on how to create queries, see the
+[MongoDB section on querying](http://www.mongodb.org/display/DOCS/Querying).
+
+```javascript
+ var mongodb = require('mongodb');
+ var server = new mongodb.Server("127.0.0.1", 27017, {});
+ new mongodb.Db('test', server, {}).open(function (error, client) {
+ if (error) throw error;
+ var collection = new mongodb.Collection(client, 'test_collection');
+ collection.find({}, {limit:10}).toArray(function(err, docs) {
+ console.dir(docs);
+ });
+ });
+```
+
+Insert
+------
+
+Signature:
+
+```javascript
+ collection.insert(docs, options, [callback]);
+```
+
+where `docs` can be a single document or an array of documents.
+
+Useful options:
+
+* `safe:true` Should always set if you have a callback.
+
+See also: [MongoDB docs for insert](http://www.mongodb.org/display/DOCS/Inserting).
+
+```javascript
+ var mongodb = require('mongodb');
+ var server = new mongodb.Server("127.0.0.1", 27017, {});
+ new mongodb.Db('test', server, {w: 1}).open(function (error, client) {
+ if (error) throw error;
+ var collection = new mongodb.Collection(client, 'test_collection');
+ collection.insert({hello: 'world'}, {safe:true},
+ function(err, objects) {
+ if (err) console.warn(err.message);
+ if (err && err.message.indexOf('E11000 ') !== -1) {
+ // this _id was already inserted in the database
+ }
+ });
+ });
+```
+
+Note that there's no reason to pass a callback to the insert or update commands
+unless you use the `safe:true` option. If you don't specify `safe:true`, then
+your callback will be called immediately.
+
+Update; update and insert (upsert)
+----------------------------------
+
+The update operation will update the first document that matches your query
+(or all documents that match if you use `multi:true`).
+If `safe:true`, `upsert` is not set, and no documents match, your callback will return 0 documents updated.
+
+See the [MongoDB docs](http://www.mongodb.org/display/DOCS/Updating) for
+the modifier (`$inc`, `$set`, `$push`, etc.) formats.
+
+Signature:
+
+```javascript
+ collection.update(criteria, objNew, options, [callback]);
+```
+
+Useful options:
+
+* `safe:true` Should always set if you have a callback.
+* `multi:true` If set, all matching documents are updated, not just the first.
+* `upsert:true` Atomically inserts the document if no documents matched.
+
+Example for `update`:
+
+```javascript
+ var mongodb = require('mongodb');
+ var server = new mongodb.Server("127.0.0.1", 27017, {});
+ new mongodb.Db('test', server, {w: 1}).open(function (error, client) {
+ if (error) throw error;
+ var collection = new mongodb.Collection(client, 'test_collection');
+ collection.update({hi: 'here'}, {$set: {hi: 'there'}}, {safe:true},
+ function(err) {
+ if (err) console.warn(err.message);
+ else console.log('successfully updated');
+ });
+ });
+```
+
+Find and modify
+---------------
+
+`findAndModify` is like `update`, but it also gives the updated document to
+your callback. But there are a few key differences between findAndModify and
+update:
+
+ 1. The signatures differ.
+ 2. You can only findAndModify a single item, not multiple items.
+
+Signature:
+
+```javascript
+ collection.findAndModify(query, sort, update, options, callback)
+```
+
+The sort parameter is used to specify which object to operate on, if more than
+one document matches. It takes the same format as the cursor sort (see
+Connection.find above).
+
+See the
+[MongoDB docs for findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command)
+for more details.
+
+Useful options:
+
+* `remove:true` set to a true to remove the object before returning
+* `new:true` set to true if you want to return the modified object rather than the original. Ignored for remove.
+* `upsert:true` Atomically inserts the document if no documents matched.
+
+Example for `findAndModify`:
+
+```javascript
+ var mongodb = require('mongodb');
+ var server = new mongodb.Server("127.0.0.1", 27017, {});
+ new mongodb.Db('test', server, {w: 1}).open(function (error, client) {
+ if (error) throw error;
+ var collection = new mongodb.Collection(client, 'test_collection');
+ collection.findAndModify({hello: 'world'}, [['_id','asc']], {$set: {hi: 'there'}}, {},
+ function(err, object) {
+ if (err) console.warn(err.message);
+ else console.dir(object); // undefined if no matching object exists.
+ });
+ });
+```
+
+Save
+----
+
+The `save` method is a shorthand for upsert if the document contains an
+`_id`, or an insert if there is no `_id`.
+
+Sponsors
+========
+Just as Felix Geisendörfer I'm also working on the driver for my own startup and this driver is a big project that also benefits other companies who are using MongoDB.
+
+If your company could benefit from a even better-engineered node.js mongodb driver I would appreciate any type of sponsorship you may be able to provide. All the sponsors will get a lifetime display in this readme, priority support and help on problems and votes on the roadmap decisions for the driver. If you are interested contact me on [christkv AT g m a i l.com](mailto:christkv@gmail.com) for details.
+
+And I'm very thankful for code contributions. If you are interested in working on features please contact me so we can discuss API design and testing.
+
+Release Notes
+=============
+
+See HISTORY
+
+Credits
+=======
+
+1. [10gen](http://github.com/mongodb/mongo-ruby-driver/)
+2. [Google Closure Library](http://code.google.com/closure/library/)
+3. [Jonas Raoni Soares Silva](http://jsfromhell.com/classes/binary-parser)
+
+Contributors
+============
+
+Aaron Heckmann, Christoph Pojer, Pau Ramon Revilla, Nathan White, Emmerman, Seth LaForge, Boris Filipov, Stefan Schärmeli, Tedde Lundgren, renctan, Sergey Ukustov, Ciaran Jessup, kuno, srimonti, Erik Abele, Pratik Daga, Slobodan Utvic, Kristina Chodorow, Yonathan Randolph, Brian Noguchi, Sam Epstein, James Harrison Fisher, Vladimir Dronnikov, Ben Hockey, Henrik Johansson, Simon Weare, Alex Gorbatchev, Shimon Doodkin, Kyle Mueller, Eran Hammer-Lahav, Marcin Ciszak, François de Metz, Vinay Pulim, nstielau, Adam Wiggins, entrinzikyl, Jeremy Selier, Ian Millington, Public Keating, andrewjstone, Christopher Stott, Corey Jewett, brettkiefer, Rob Holland, Senmiao Liu, heroic, gitfy
+
+License
+=======
+
+ Copyright 2009 - 2012 Christian Amor Kvalheim.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/node_modules/mongodb/index.js b/node_modules/mongodb/index.js
new file mode 100755
index 0000000..4f59e9d
--- /dev/null
+++ b/node_modules/mongodb/index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/mongodb');
diff --git a/node_modules/mongodb/install.js b/node_modules/mongodb/install.js
new file mode 100644
index 0000000..f9f2a57
--- /dev/null
+++ b/node_modules/mongodb/install.js
@@ -0,0 +1,40 @@
+var spawn = require('child_process').spawn,
+ exec = require('child_process').exec;
+
+process.stdout.write("================================================================================\n");
+process.stdout.write("= =\n");
+process.stdout.write("= To install with C++ bson parser do =\n");
+process.stdout.write("= =\n");
+process.stdout.write("================================================================================\n");
+
+// Check if we want to build the native code
+var build_native = process.env['npm_package_config_native'] != null ? process.env['npm_package_config_native'] : 'false';
+build_native = build_native == 'true' ? true : false;
+// If we are building the native bson extension ensure we use gmake if available
+if(build_native) {
+ // Check if we need to use gmake
+ exec('which gmake', function(err, stdout, stderr) {
+ // Set up spawn command
+ var make = null;
+ // No gmake build using make
+ if(err != null) {
+ make = spawn('make', ['total']);
+ } else {
+ make = spawn('gmake', ['total']);
+ }
+
+ // Execute spawn
+ make.stdout.on('data', function(data) {
+ process.stdout.write(data);
+ })
+
+ make.stderr.on('data', function(data) {
+ process.stdout.write(data);
+ })
+
+ make.on('exit', function(code) {
+ process.stdout.write('child process exited with code ' + code + "\n");
+ })
+ });
+}
+
diff --git a/node_modules/mongodb/lib/mongodb/admin.js b/node_modules/mongodb/lib/mongodb/admin.js
new file mode 100644
index 0000000..6e9cd30
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/admin.js
@@ -0,0 +1,339 @@
+/*!
+ * Module dependencies.
+ */
+var Collection = require('./collection').Collection,
+ Cursor = require('./cursor').Cursor,
+ DbCommand = require('./commands/db_command').DbCommand,
+ utils = require('./utils');
+
+/**
+ * Allows the user to access the admin functionality of MongoDB
+ *
+ * @class Represents the Admin methods of MongoDB.
+ * @param {Object} db Current db instance we wish to perform Admin operations on.
+ * @return {Function} Constructor for Admin type.
+ */
+function Admin(db) {
+ if(!(this instanceof Admin)) return new Admin(db);
+ this.db = db;
+};
+
+/**
+ * Retrieve the server information for the current
+ * instance of the db client
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from buildInfo or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.buildInfo = function(callback) {
+ this.serverInfo(callback);
+}
+
+/**
+ * Retrieve the server information for the current
+ * instance of the db client
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from serverInfo or null if an error occured.
+ * @return {null} Returns no result
+ * @api private
+ */
+Admin.prototype.serverInfo = function(callback) {
+ this.db.executeDbAdminCommand({buildinfo:1}, function(err, doc) {
+ if(err != null) return callback(err, null);
+ return callback(null, doc.documents[0]);
+ });
+}
+
+/**
+ * Retrieve this db's server status.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from serverStatus or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Admin.prototype.serverStatus = function(callback) {
+ var self = this;
+
+ this.db.executeDbAdminCommand({serverStatus: 1}, function(err, doc) {
+ if(err == null && doc.documents[0].ok === 1) {
+ callback(null, doc.documents[0]);
+ } else {
+ if(err) return callback(err, false);
+ return callback(utils.toError(doc.documents[0]), false);
+ }
+ });
+};
+
+/**
+ * Retrieve the current profiling Level for MongoDB
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from profilingLevel or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.profilingLevel = function(callback) {
+ var self = this;
+
+ this.db.executeDbAdminCommand({profile:-1}, function(err, doc) {
+ doc = doc.documents[0];
+
+ if(err == null && doc.ok === 1) {
+ var was = doc.was;
+ if(was == 0) return callback(null, "off");
+ if(was == 1) return callback(null, "slow_only");
+ if(was == 2) return callback(null, "all");
+ return callback(new Error("Error: illegal profiling level value " + was), null);
+ } else {
+ err != null ? callback(err, null) : callback(new Error("Error with profile command"), null);
+ }
+ });
+};
+
+/**
+ * Ping the MongoDB server and retrieve results
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from ping or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.ping = function(options, callback) {
+ // Unpack calls
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+
+ this.db.executeDbAdminCommand({ping: 1}, callback);
+}
+
+/**
+ * Authenticate against MongoDB
+ *
+ * @param {String} username The user name for the authentication.
+ * @param {String} password The password for the authentication.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from authenticate or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.authenticate = function(username, password, callback) {
+ this.db.authenticate(username, password, {authdb: 'admin'}, function(err, doc) {
+ return callback(err, doc);
+ })
+}
+
+/**
+ * Logout current authenticated user
+ *
+ * @param {Object} [options] Optional parameters to the command.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from logout or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.logout = function(callback) {
+ this.db.logout({authdb: 'admin'}, function(err, doc) {
+ return callback(err, doc);
+ })
+}
+
+/**
+ * Add a user to the MongoDB server, if the user exists it will
+ * overwrite the current password
+ *
+ * Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {String} username The user name for the authentication.
+ * @param {String} password The password for the authentication.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from addUser or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.addUser = function(username, password, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = args.pop();
+ options = args.length ? args.shift() : {};
+
+ options.dbName = 'admin';
+ // Add user
+ this.db.addUser(username, password, options, function(err, doc) {
+ return callback(err, doc);
+ })
+}
+
+/**
+ * Remove a user from the MongoDB server
+ *
+ * Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {String} username The user name for the authentication.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from removeUser or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.removeUser = function(username, options, callback) {
+ var self = this;
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ options = args.length ? args.shift() : {};
+ options.dbName = 'admin';
+
+ this.db.removeUser(username, options, function(err, doc) {
+ return callback(err, doc);
+ })
+}
+
+/**
+ * Set the current profiling level of MongoDB
+ *
+ * @param {String} level The new profiling level (off, slow_only, all)
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from setProfilingLevel or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.setProfilingLevel = function(level, callback) {
+ var self = this;
+ var command = {};
+ var profile = 0;
+
+ if(level == "off") {
+ profile = 0;
+ } else if(level == "slow_only") {
+ profile = 1;
+ } else if(level == "all") {
+ profile = 2;
+ } else {
+ return callback(new Error("Error: illegal profiling level value " + level));
+ }
+
+ // Set up the profile number
+ command['profile'] = profile;
+
+ this.db.executeDbAdminCommand(command, function(err, doc) {
+ doc = doc.documents[0];
+
+ if(err == null && doc.ok === 1)
+ return callback(null, level);
+ return err != null ? callback(err, null) : callback(new Error("Error with profile command"), null);
+ });
+};
+
+/**
+ * Retrive the current profiling information for MongoDB
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from profilingInfo or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.profilingInfo = function(callback) {
+ try {
+ new Cursor(this.db, new Collection(this.db, DbCommand.SYSTEM_PROFILE_COLLECTION), {}, {}, {dbName: 'admin'}).toArray(function(err, items) {
+ return callback(err, items);
+ });
+ } catch (err) {
+ return callback(err, null);
+ }
+};
+
+/**
+ * Execute a db command against the Admin database
+ *
+ * @param {Object} command A command object `{ping:1}`.
+ * @param {Object} [options] Optional parameters to the command.
+ * @param {Function} callback this will be called after executing this method. The command always return the whole result of the command as the second parameter.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.command = function(command, options, callback) {
+ var self = this;
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ options = args.length ? args.shift() : {};
+
+ // Execute a command
+ this.db.executeDbAdminCommand(command, options, function(err, doc) {
+ // Ensure change before event loop executes
+ return callback != null ? callback(err, doc) : null;
+ });
+}
+
+/**
+ * Validate an existing collection
+ *
+ * @param {String} collectionName The name of the collection to validate.
+ * @param {Object} [options] Optional parameters to the command.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from validateCollection or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.validateCollection = function(collectionName, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ options = args.length ? args.shift() : {};
+
+ var self = this;
+ var command = {validate: collectionName};
+ var keys = Object.keys(options);
+
+ // Decorate command with extra options
+ for(var i = 0; i < keys.length; i++) {
+ if(options.hasOwnProperty(keys[i])) {
+ command[keys[i]] = options[keys[i]];
+ }
+ }
+
+ this.db.executeDbCommand(command, function(err, doc) {
+ if(err != null) return callback(err, null);
+ doc = doc.documents[0];
+
+ if(doc.ok === 0)
+ return callback(new Error("Error with validate command"), null);
+ if(doc.result != null && doc.result.constructor != String)
+ return callback(new Error("Error with validation data"), null);
+ if(doc.result != null && doc.result.match(/exception|corrupt/) != null)
+ return callback(new Error("Error: invalid collection " + collectionName), null);
+ if(doc.valid != null && !doc.valid)
+ return callback(new Error("Error: invalid collection " + collectionName), null);
+
+ return callback(null, doc);
+ });
+};
+
+/**
+ * List the available databases
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from listDatabases or null if an error occured.
+ * @return {null} Returns no result
+ * @api public
+ */
+Admin.prototype.listDatabases = function(callback) {
+ // Execute the listAllDatabases command
+ this.db.executeDbAdminCommand({listDatabases:1}, {}, function(err, doc) {
+ if(err != null) return callback(err, null);
+ return callback(null, doc.documents[0]);
+ });
+}
+
+/**
+ * Get ReplicaSet status
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from replSetGetStatus or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Admin.prototype.replSetGetStatus = function(callback) {
+ var self = this;
+
+ this.db.executeDbAdminCommand({replSetGetStatus:1}, function(err, doc) {
+ if(err == null && doc.documents[0].ok === 1)
+ return callback(null, doc.documents[0]);
+ if(err) return callback(err, false);
+ return callback(utils.toError(doc.documents[0]), false);
+ });
+};
+
+/**
+ * @ignore
+ */
+exports.Admin = Admin;
diff --git a/node_modules/mongodb/lib/mongodb/auth/mongodb_cr.js b/node_modules/mongodb/lib/mongodb/auth/mongodb_cr.js
new file mode 100644
index 0000000..51b09b1
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/auth/mongodb_cr.js
@@ -0,0 +1,53 @@
+var DbCommand = require('../commands/db_command').DbCommand
+ , utils = require('../utils');
+
+var authenticate = function(db, username, password, authdb, options, callback) {
+ var numberOfConnections = 0;
+ var errorObject = null;
+
+ if(options['connection'] != null) {
+ //if a connection was explicitly passed on options, then we have only one...
+ numberOfConnections = 1;
+ } else {
+ // Get the amount of connections in the pool to ensure we have authenticated all comments
+ numberOfConnections = db.serverConfig.allRawConnections().length;
+ options['onAll'] = true;
+ }
+
+ // Execute all four
+ db._executeQueryCommand(DbCommand.createGetNonceCommand(db), options, function(err, result, connection) {
+ // Execute on all the connections
+ if(err == null) {
+ // Nonce used to make authentication request with md5 hash
+ var nonce = result.documents[0].nonce;
+ // Execute command
+ db._executeQueryCommand(DbCommand.createAuthenticationCommand(db, username, password, nonce, authdb), {connection:connection}, function(err, result) {
+ // Count down
+ numberOfConnections = numberOfConnections - 1;
+ // Ensure we save any error
+ if(err) {
+ errorObject = err;
+ } else if(result.documents[0].err != null || result.documents[0].errmsg != null){
+ errorObject = utils.toError(result.documents[0]);
+ }
+
+ // Work around the case where the number of connections are 0
+ if(numberOfConnections <= 0 && typeof callback == 'function') {
+ var internalCallback = callback;
+ callback = null;
+
+ if(errorObject == null && result.documents[0].ok == 1) {
+ // We authenticated correctly save the credentials
+ db.serverConfig.auth.add('MONGODB-CR', db.databaseName, username, password, authdb);
+ // Return callback
+ internalCallback(errorObject, true);
+ } else {
+ internalCallback(errorObject, false);
+ }
+ }
+ });
+ }
+ });
+}
+
+exports.authenticate = authenticate;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/auth/mongodb_gssapi.js b/node_modules/mongodb/lib/mongodb/auth/mongodb_gssapi.js
new file mode 100644
index 0000000..f41cd5d
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/auth/mongodb_gssapi.js
@@ -0,0 +1,148 @@
+var DbCommand = require('../commands/db_command').DbCommand
+ , utils = require('../utils')
+ , format = require('util').format;
+
+// Kerberos class
+var Kerberos = null;
+var MongoAuthProcess = null;
+// Try to grab the Kerberos class
+try {
+ Kerberos = require('kerberos').Kerberos
+ // Authentication process for Mongo
+ MongoAuthProcess = require('kerberos').processes.MongoAuthProcess
+} catch(err) {}
+
+var authenticate = function(db, username, password, authdb, options, callback) {
+ var numberOfConnections = 0;
+ var errorObject = null;
+ // We don't have the Kerberos library
+ if(Kerberos == null) return callback(new Error("Kerberos library is not installed"));
+
+ if(options['connection'] != null) {
+ //if a connection was explicitly passed on options, then we have only one...
+ numberOfConnections = 1;
+ } else {
+ // Get the amount of connections in the pool to ensure we have authenticated all comments
+ numberOfConnections = db.serverConfig.allRawConnections().length;
+ options['onAll'] = true;
+ }
+
+ // Grab all the connections
+ var connections = options['connection'] != null ? [options['connection']] : db.serverConfig.allRawConnections();
+ var error = null;
+ // Authenticate all connections
+ for(var i = 0; i < numberOfConnections; i++) {
+
+ // Start Auth process for a connection
+ GSSAPIInitialize(db, username, password, authdb, connections[i], function(err, result) {
+ // Adjust number of connections left to connect
+ numberOfConnections = numberOfConnections - 1;
+ // If we have an error save it
+ if(err) error = err;
+
+ // We are done
+ if(numberOfConnections == 0) {
+ if(err) return callback(error, false);
+ // We authenticated correctly save the credentials
+ db.serverConfig.auth.add('GSSAPI', db.databaseName, username, password, authdb);
+ // Return valid callback
+ return callback(null, true);
+ }
+ });
+ }
+}
+
+//
+// Initialize step
+var GSSAPIInitialize = function(db, username, password, authdb, connection, callback) {
+ // Create authenticator
+ var mongo_auth_process = new MongoAuthProcess(connection.socketOptions.host, connection.socketOptions.port);
+
+ // Perform initialization
+ mongo_auth_process.init(username, password, function(err, context) {
+ if(err) return callback(err, false);
+
+ // Perform the first step
+ mongo_auth_process.transition('', function(err, payload) {
+ if(err) return callback(err, false);
+
+ // Call the next db step
+ MongoDBGSSAPIFirstStep(mongo_auth_process, payload, db, username, password, authdb, connection, callback);
+ });
+ });
+}
+
+//
+// Perform first step against mongodb
+var MongoDBGSSAPIFirstStep = function(mongo_auth_process, payload, db, username, password, authdb, connection, callback) {
+ // Build the sasl start command
+ var command = {
+ saslStart: 1
+ , mechanism: 'GSSAPI'
+ , payload: payload
+ , autoAuthorize: 1
+ };
+
+ // Execute first sasl step
+ db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
+ if(err) return callback(err, false);
+ // Get the payload
+ doc = doc.documents[0];
+ var db_payload = doc.payload;
+
+ mongo_auth_process.transition(doc.payload, function(err, payload) {
+ if(err) return callback(err, false);
+
+ // MongoDB API Second Step
+ MongoDBGSSAPISecondStep(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback);
+ });
+ });
+}
+
+//
+// Perform first step against mongodb
+var MongoDBGSSAPISecondStep = function(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback) {
+ // Build Authentication command to send to MongoDB
+ var command = {
+ saslContinue: 1
+ , conversationId: doc.conversationId
+ , payload: payload
+ };
+
+ // Execute the command
+ db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
+ if(err) return callback(err, false);
+
+ // Get the result document
+ doc = doc.documents[0];
+
+ // Call next transition for kerberos
+ mongo_auth_process.transition(doc.payload, function(err, payload) {
+ if(err) return callback(err, false);
+
+ // Call the last and third step
+ MongoDBGSSAPIThirdStep(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback);
+ });
+ });
+}
+
+var MongoDBGSSAPIThirdStep = function(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback) {
+ // Build final command
+ var command = {
+ saslContinue: 1
+ , conversationId: doc.conversationId
+ , payload: payload
+ };
+
+ // Let's finish the auth process against mongodb
+ db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
+ if(err) return callback(err, false);
+
+ mongo_auth_process.transition(null, function(err, payload) {
+ if(err) return callback(err, false);
+ callback(null, true);
+ });
+ });
+}
+
+exports.authenticate = authenticate;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/auth/mongodb_sspi.js b/node_modules/mongodb/lib/mongodb/auth/mongodb_sspi.js
new file mode 100644
index 0000000..1990efd
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/auth/mongodb_sspi.js
@@ -0,0 +1,134 @@
+var DbCommand = require('../commands/db_command').DbCommand
+ , utils = require('../utils')
+ , format = require('util').format;
+
+// Kerberos class
+var Kerberos = null;
+var MongoAuthProcess = null;
+// Try to grab the Kerberos class
+try {
+ Kerberos = require('kerberos').Kerberos
+ // Authentication process for Mongo
+ MongoAuthProcess = require('kerberos').processes.MongoAuthProcess
+} catch(err) {}
+
+var authenticate = function(db, username, password, authdb, options, callback) {
+ var numberOfConnections = 0;
+ var errorObject = null;
+ // We don't have the Kerberos library
+ if(Kerberos == null) return callback(new Error("Kerberos library is not installed"));
+
+ if(options['connection'] != null) {
+ //if a connection was explicitly passed on options, then we have only one...
+ numberOfConnections = 1;
+ } else {
+ // Get the amount of connections in the pool to ensure we have authenticated all comments
+ numberOfConnections = db.serverConfig.allRawConnections().length;
+ options['onAll'] = true;
+ }
+
+ var connection = db.serverConfig.allRawConnections()[0];
+
+ // Grab all the connections
+ var connections = db.serverConfig.allRawConnections();
+ var error = null;
+
+ // Authenticate all connections
+ for(var i = 0; i < numberOfConnections; i++) {
+ // Start Auth process for a connection
+ SSIPAuthenticate(db, username, password, authdb, connections[i], function(err, result) {
+ // Adjust number of connections left to connect
+ numberOfConnections = numberOfConnections - 1;
+ // If we have an error save it
+ if(err) error = err;
+
+ // We are done
+ if(numberOfConnections == 0) {
+ if(err) return callback(err, false);
+ // We authenticated correctly save the credentials
+ db.serverConfig.auth.add('GSSAPI', db.databaseName, username, password, authdb);
+ // Return valid callback
+ return callback(null, true);
+ }
+ });
+ }
+}
+
+var SSIPAuthenticate = function(db, username, password, authdb, connection, callback) {
+ // --------------------------------------------------------------
+ // Async Version
+ // --------------------------------------------------------------
+ var command = {
+ saslStart: 1
+ , mechanism: 'GSSAPI'
+ , payload: ''
+ , autoAuthorize: 1
+ };
+
+ // Create authenticator
+ var mongo_auth_process = new MongoAuthProcess(connection.socketOptions.host, connection.socketOptions.port);
+
+ // Execute first sasl step
+ db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
+ if(err) return callback(err);
+ doc = doc.documents[0];
+
+ mongo_auth_process.init(username, password, function(err) {
+ if(err) return callback(err);
+
+ mongo_auth_process.transition(doc.payload, function(err, payload) {
+ if(err) return callback(err);
+
+ // Perform the next step against mongod
+ var command = {
+ saslContinue: 1
+ , conversationId: doc.conversationId
+ , payload: payload
+ };
+
+ // Execute the command
+ db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
+ if(err) return callback(err);
+ doc = doc.documents[0];
+
+ mongo_auth_process.transition(doc.payload, function(err, payload) {
+ if(err) return callback(err);
+
+ // Perform the next step against mongod
+ var command = {
+ saslContinue: 1
+ , conversationId: doc.conversationId
+ , payload: payload
+ };
+
+ // Execute the command
+ db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
+ if(err) return callback(err);
+ doc = doc.documents[0];
+
+ mongo_auth_process.transition(doc.payload, function(err, payload) {
+ // Perform the next step against mongod
+ var command = {
+ saslContinue: 1
+ , conversationId: doc.conversationId
+ , payload: payload
+ };
+
+ // Execute the command
+ db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
+ if(err) return callback(err);
+ doc = doc.documents[0];
+
+ if(doc.done) return callback(null, true);
+ callback(new Error("Authentication failed"), false);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+}
+
+exports.authenticate = authenticate;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/collection.js b/node_modules/mongodb/lib/mongodb/collection.js
new file mode 100644
index 0000000..e0b792b
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/collection.js
@@ -0,0 +1,1759 @@
+/**
+ * Module dependencies.
+ * @ignore
+ */
+var InsertCommand = require('./commands/insert_command').InsertCommand
+ , QueryCommand = require('./commands/query_command').QueryCommand
+ , DeleteCommand = require('./commands/delete_command').DeleteCommand
+ , UpdateCommand = require('./commands/update_command').UpdateCommand
+ , DbCommand = require('./commands/db_command').DbCommand
+ , ObjectID = require('bson').ObjectID
+ , Code = require('bson').Code
+ , Cursor = require('./cursor').Cursor
+ , utils = require('./utils');
+
+/**
+ * Precompiled regexes
+ * @ignore
+**/
+const eErrorMessages = /No matching object found/;
+
+/**
+ * toString helper.
+ * @ignore
+ */
+var toString = Object.prototype.toString;
+
+/**
+ * Create a new Collection instance (INTERNAL TYPE)
+ *
+ * Options
+ * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * - **slaveOk** {Boolean, default:false}, Allow reads from secondaries.
+ * - **serializeFunctions** {Boolean, default:false}, serialize functions on the document.
+ * - **raw** {Boolean, default:false}, perform all operations using raw bson objects.
+ * - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation.
+ *
+ * @class Represents a Collection
+ * @param {Object} db db instance.
+ * @param {String} collectionName collection name.
+ * @param {Object} [pkFactory] alternative primary key factory.
+ * @param {Object} [options] additional options for the collection.
+ * @return {Object} a collection instance.
+ */
+function Collection (db, collectionName, pkFactory, options) {
+ if(!(this instanceof Collection)) return new Collection(db, collectionName, pkFactory, options);
+
+ checkCollectionName(collectionName);
+
+ this.db = db;
+ this.collectionName = collectionName;
+ this.internalHint = null;
+ this.opts = options != null && ('object' === typeof options) ? options : {};
+ this.slaveOk = options == null || options.slaveOk == null ? db.slaveOk : options.slaveOk;
+ this.serializeFunctions = options == null || options.serializeFunctions == null ? db.serializeFunctions : options.serializeFunctions;
+ this.raw = options == null || options.raw == null ? db.raw : options.raw;
+
+ this.readPreference = options == null || options.readPreference == null ? db.serverConfig.options.readPreference : options.readPreference;
+ this.readPreference = this.readPreference == null ? 'primary' : this.readPreference;
+
+ this.pkFactory = pkFactory == null
+ ? ObjectID
+ : pkFactory;
+
+ var self = this;
+}
+
+/**
+ * Inserts a single document or a an array of documents into MongoDB.
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **continueOnError/keepGoing** {Boolean, default:false}, keep inserting documents even if one document has an error, *mongodb 1.9.1 >*.
+ * - **serializeFunctions** {Boolean, default:false}, serialize functions on the document.
+ * - **forceServerObjectId** {Boolean, default:false}, let server assign ObjectId instead of the driver
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {Array|Object} docs
+ * @param {Object} [options] optional options for insert command
+ * @param {Function} [callback] optional callback for the function, must be provided when using a writeconcern
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.insert = function insert (docs, options, callback) {
+ if ('function' === typeof options) callback = options, options = {};
+ if(options == null) options = {};
+ if(!('function' === typeof callback)) callback = null;
+ var self = this;
+ insertAll(self, Array.isArray(docs) ? docs : [docs], options, callback);
+ return this;
+};
+
+/**
+ * @ignore
+ */
+var checkCollectionName = function checkCollectionName (collectionName) {
+ if ('string' !== typeof collectionName) {
+ throw Error("collection name must be a String");
+ }
+
+ if (!collectionName || collectionName.indexOf('..') != -1) {
+ throw Error("collection names cannot be empty");
+ }
+
+ if (collectionName.indexOf('$') != -1 &&
+ collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null) {
+ throw Error("collection names must not contain '$'");
+ }
+
+ if (collectionName.match(/^\.|\.$/) != null) {
+ throw Error("collection names must not start or end with '.'");
+ }
+};
+
+/**
+ * Removes documents specified by `selector` from the db.
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **single** {Boolean, default:false}, removes the first document found.
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {Object} [selector] optional select, no selector is equivalent to removing all documents.
+ * @param {Object} [options] additional options during remove.
+ * @param {Function} [callback] must be provided if you performing a remove with a writeconcern
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.remove = function remove(selector, options, callback) {
+ if ('function' === typeof selector) {
+ callback = selector;
+ selector = options = {};
+ } else if ('function' === typeof options) {
+ callback = options;
+ options = {};
+ }
+
+ // Ensure options
+ if(options == null) options = {};
+ if(!('function' === typeof callback)) callback = null;
+ // Ensure we have at least an empty selector
+ selector = selector == null ? {} : selector;
+ // Set up flags for the command, if we have a single document remove
+ var flags = 0 | (options.single ? 1 : 0);
+
+ // DbName
+ var dbName = options['dbName'];
+ // If no dbname defined use the db one
+ if(dbName == null) {
+ dbName = this.db.databaseName;
+ }
+
+ // Create a delete command
+ var deleteCommand = new DeleteCommand(
+ this.db
+ , dbName + "." + this.collectionName
+ , selector
+ , flags);
+
+ var self = this;
+ var errorOptions = _getWriteConcern(self, options, callback);
+ // Execute the command, do not add a callback as it's async
+ if(_hasWriteConcern(errorOptions) && typeof callback == 'function') {
+ // Insert options
+ var commandOptions = {read:false};
+ // If we have safe set set async to false
+ if(errorOptions == null) commandOptions['async'] = true;
+ // Set safe option
+ commandOptions['safe'] = true;
+ // If we have an error option
+ if(typeof errorOptions == 'object') {
+ var keys = Object.keys(errorOptions);
+ for(var i = 0; i < keys.length; i++) {
+ commandOptions[keys[i]] = errorOptions[keys[i]];
+ }
+ }
+
+ // Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection)
+ this.db._executeRemoveCommand(deleteCommand, commandOptions, function (err, error) {
+ error = error && error.documents;
+ if(!callback) return;
+
+ if(err) {
+ callback(err);
+ } else if(error[0].err || error[0].errmsg) {
+ callback(utils.toError(error[0]));
+ } else {
+ callback(null, error[0].n);
+ }
+ });
+ } else if(_hasWriteConcern(errorOptions) && callback == null) {
+ throw new Error("Cannot use a writeConcern without a provided callback");
+ } else {
+ var result = this.db._executeRemoveCommand(deleteCommand);
+ // If no callback just return
+ if (!callback) return;
+ // If error return error
+ if (result instanceof Error) {
+ return callback(result);
+ }
+ // Otherwise just return
+ return callback();
+ }
+};
+
+/**
+ * Renames the collection.
+ *
+ * Options
+ * - **dropTarget** {Boolean, default:false}, drop the target name collection if it previously exists.
+ *
+ * @param {String} newName the new name of the collection.
+ * @param {Object} [options] returns option results.
+ * @param {Function} callback the callback accepting the result
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.rename = function rename (newName, options, callback) {
+ var self = this;
+
+ if(typeof options == 'function') {
+ callback = options;
+ options = {}
+ }
+
+ // Ensure the new name is valid
+ checkCollectionName(newName);
+ // Execute the command, return the new renamed collection if successful
+ self.db._executeQueryCommand(DbCommand.createRenameCollectionCommand(self.db, self.collectionName, newName, options), function(err, result) {
+ if(err == null && result.documents[0].ok == 1) {
+ if(callback != null) {
+ // Set current object to point to the new name
+ self.collectionName = newName;
+ // Return the current collection
+ callback(null, self);
+ }
+ } else if(result.documents[0].errmsg != null) {
+ if(null != callback) {
+ if (null == err) {
+ err = utils.toError(result.documents[0]);
+ }
+ callback(err, null);
+ }
+ }
+ });
+};
+
+/**
+ * @ignore
+ */
+var insertAll = function insertAll (self, docs, options, callback) {
+ if('function' === typeof options) callback = options, options = {};
+ if(options == null) options = {};
+ if(!('function' === typeof callback)) callback = null;
+
+ // Insert options (flags for insert)
+ var insertFlags = {};
+ // If we have a mongodb version >= 1.9.1 support keepGoing attribute
+ if(options['keepGoing'] != null) {
+ insertFlags['keepGoing'] = options['keepGoing'];
+ }
+
+ // If we have a mongodb version >= 1.9.1 support keepGoing attribute
+ if(options['continueOnError'] != null) {
+ insertFlags['continueOnError'] = options['continueOnError'];
+ }
+
+ // DbName
+ var dbName = options['dbName'];
+ // If no dbname defined use the db one
+ if(dbName == null) {
+ dbName = self.db.databaseName;
+ }
+
+ // Either use override on the function, or go back to default on either the collection
+ // level or db
+ if(options['serializeFunctions'] != null) {
+ insertFlags['serializeFunctions'] = options['serializeFunctions'];
+ } else {
+ insertFlags['serializeFunctions'] = self.serializeFunctions;
+ }
+
+ // Pass in options
+ var insertCommand = new InsertCommand(
+ self.db
+ , dbName + "." + self.collectionName, true, insertFlags);
+
+ // Add the documents and decorate them with id's if they have none
+ for(var index = 0, len = docs.length; index < len; ++index) {
+ var doc = docs[index];
+
+ // Add id to each document if it's not already defined
+ if (!(Buffer.isBuffer(doc))
+ && doc['_id'] == null
+ && self.db.forceServerObjectId != true
+ && options.forceServerObjectId != true) {
+ doc['_id'] = self.pkFactory.createPk();
+ }
+
+ insertCommand.add(doc);
+ }
+
+ // Collect errorOptions
+ var errorOptions = _getWriteConcern(self, options, callback);
+ // Default command options
+ var commandOptions = {};
+ // If safe is defined check for error message
+ if(_hasWriteConcern(errorOptions) && typeof callback == 'function') {
+ // Insert options
+ commandOptions['read'] = false;
+ // If we have safe set set async to false
+ if(errorOptions == null) commandOptions['async'] = true;
+
+ // Set safe option
+ commandOptions['safe'] = errorOptions;
+ // If we have an error option
+ if(typeof errorOptions == 'object') {
+ var keys = Object.keys(errorOptions);
+ for(var i = 0; i < keys.length; i++) {
+ commandOptions[keys[i]] = errorOptions[keys[i]];
+ }
+ }
+
+ // Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection)
+ self.db._executeInsertCommand(insertCommand, commandOptions, function (err, error) {
+ error = error && error.documents;
+ if(!callback) return;
+
+ if (err) {
+ callback(err);
+ } else if(error[0].err || error[0].errmsg) {
+ callback(utils.toError(error[0]));
+ } else {
+ callback(null, docs);
+ }
+ });
+ } else if(_hasWriteConcern(errorOptions) && callback == null) {
+ throw new Error("Cannot use a writeConcern without a provided callback");
+ } else {
+ // Execute the call without a write concern
+ var result = self.db._executeInsertCommand(insertCommand, commandOptions);
+ // If no callback just return
+ if(!callback) return;
+ // If error return error
+ if(result instanceof Error) {
+ return callback(result);
+ }
+ // Otherwise just return
+ return callback(null, docs);
+ }
+};
+
+/**
+ * Save a document. Simple full document replacement function. Not recommended for efficiency, use atomic
+ * operators and update instead for more efficient operations.
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {Object} [doc] the document to save
+ * @param {Object} [options] additional options during remove.
+ * @param {Function} [callback] must be provided if you performing a safe save
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.save = function save(doc, options, callback) {
+ if('function' === typeof options) callback = options, options = null;
+ if(options == null) options = {};
+ if(!('function' === typeof callback)) callback = null;
+ // Throw an error if attempting to perform a bulk operation
+ if(Array.isArray(doc)) throw new Error("doc parameter must be a single document");
+ // Extract the id, if we have one we need to do a update command
+ var id = doc['_id'];
+ var commandOptions = _getWriteConcern(this, options, callback);
+
+ if(id) {
+ commandOptions.upsert = true;
+ this.update({ _id: id }, doc, commandOptions, callback);
+ } else {
+ this.insert(doc, commandOptions, callback && function (err, docs) {
+ if (err) return callback(err, null);
+
+ if (Array.isArray(docs)) {
+ callback(err, docs[0]);
+ } else {
+ callback(err, docs);
+ }
+ });
+ }
+};
+
+/**
+ * Updates documents.
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **upsert** {Boolean, default:false}, perform an upsert operation.
+ * - **multi** {Boolean, default:false}, update all documents matching the selector.
+ * - **serializeFunctions** {Boolean, default:false}, serialize functions on the document.
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {Object} selector the query to select the document/documents to be updated
+ * @param {Object} document the fields/vals to be updated, or in the case of an upsert operation, inserted.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} [callback] must be provided if you performing an update with a writeconcern
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.update = function update(selector, document, options, callback) {
+ if('function' === typeof options) callback = options, options = null;
+ if(options == null) options = {};
+ if(!('function' === typeof callback)) callback = null;
+
+ // DbName
+ var dbName = options['dbName'];
+ // If no dbname defined use the db one
+ if(dbName == null) {
+ dbName = this.db.databaseName;
+ }
+
+ // If we are not providing a selector or document throw
+ if(selector == null || typeof selector != 'object') return callback(new Error("selector must be a valid JavaScript object"));
+ if(document == null || typeof document != 'object') return callback(new Error("document must be a valid JavaScript object"));
+
+ // Either use override on the function, or go back to default on either the collection
+ // level or db
+ if(options['serializeFunctions'] != null) {
+ options['serializeFunctions'] = options['serializeFunctions'];
+ } else {
+ options['serializeFunctions'] = this.serializeFunctions;
+ }
+
+ var updateCommand = new UpdateCommand(
+ this.db
+ , dbName + "." + this.collectionName
+ , selector
+ , document
+ , options);
+
+ var self = this;
+ // Unpack the error options if any
+ var errorOptions = _getWriteConcern(this, options, callback);
+ // If safe is defined check for error message
+ if(_hasWriteConcern(errorOptions) && typeof callback == 'function') {
+ // Insert options
+ var commandOptions = {read:false};
+ // If we have safe set set async to false
+ if(errorOptions == null) commandOptions['async'] = true;
+ // Set safe option
+ commandOptions['safe'] = errorOptions;
+ // If we have an error option
+ if(typeof errorOptions == 'object') {
+ var keys = Object.keys(errorOptions);
+ for(var i = 0; i < keys.length; i++) {
+ commandOptions[keys[i]] = errorOptions[keys[i]];
+ }
+ }
+
+ // Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection)
+ this.db._executeUpdateCommand(updateCommand, commandOptions, function (err, error) {
+ error = error && error.documents;
+ if(!callback) return;
+
+ if(err) {
+ callback(err);
+ } else if(error[0].err || error[0].errmsg) {
+ callback(utils.toError(error[0]));
+ } else {
+ // Perform the callback
+ callback(null, error[0].n, error[0]);
+ }
+ });
+ } else if(_hasWriteConcern(errorOptions) && callback == null) {
+ throw new Error("Cannot use a writeConcern without a provided callback");
+ } else {
+ // Execute update
+ var result = this.db._executeUpdateCommand(updateCommand);
+ // If no callback just return
+ if (!callback) return;
+ // If error return error
+ if (result instanceof Error) {
+ return callback(result);
+ }
+ // Otherwise just return
+ return callback();
+ }
+};
+
+/**
+ * The distinct command returns returns a list of distinct values for the given key across a collection.
+ *
+ * Options
+ * - **readPreference** {String}, the preferred read preference (Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ *
+ * @param {String} key key to run distinct against.
+ * @param {Object} [query] option query to narrow the returned objects.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from distinct or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.distinct = function distinct(key, query, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ query = args.length ? args.shift() || {} : {};
+ options = args.length ? args.shift() || {} : {};
+
+ var mapCommandHash = {
+ 'distinct': this.collectionName
+ , 'query': query
+ , 'key': key
+ };
+
+ // Set read preference if we set one
+ var readPreference = options['readPreference'] ? options['readPreference'] : false;
+ // Create the command
+ var cmd = DbCommand.createDbSlaveOkCommand(this.db, mapCommandHash);
+
+ this.db._executeQueryCommand(cmd, {read:readPreference}, function (err, result) {
+ if(err)
+ return callback(err);
+ if(result.documents[0].ok != 1)
+ return callback(new Error(result.documents[0].errmsg));
+ callback(null, result.documents[0].values);
+ });
+};
+
+/**
+ * Count number of matching documents in the db to a query.
+ *
+ * Options
+ * - **skip** {Number}, The number of documents to skip for the count.
+ * - **limit** {Number}, The limit of documents to count.
+ * - **readPreference** {String}, the preferred read preference (Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ *
+ * @param {Object} [query] query to filter by before performing count.
+ * @param {Object} [options] additional options during count.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the count method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.count = function count (query, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ query = args.length ? args.shift() || {} : {};
+ options = args.length ? args.shift() || {} : {};
+ var skip = options.skip;
+ var limit = options.limit;
+
+ // Final query
+ var commandObject = {
+ 'count': this.collectionName
+ , 'query': query
+ , 'fields': null
+ };
+
+ // Add limit and skip if defined
+ if(typeof skip == 'number') commandObject.skip = skip;
+ if(typeof limit == 'number') commandObject.limit = limit;
+
+ // Set read preference if we set one
+ options.readPreference = _getReadConcern(this, options);
+
+ // Execute the command
+ this.db.command(commandObject, options, function(err, result) {
+ if(err) return callback(err, null);
+ return callback(null, result.n);
+ });
+};
+
+
+/**
+ * Drop the collection
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the drop method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.drop = function drop(callback) {
+ this.db.dropCollection(this.collectionName, callback);
+};
+
+/**
+ * Find and update a document.
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **remove** {Boolean, default:false}, set to true to remove the object before returning.
+ * - **upsert** {Boolean, default:false}, perform an upsert operation.
+ * - **new** {Boolean, default:false}, set to true if you want to return the modified object rather than the original. Ignored for remove.
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {Object} query query object to locate the object to modify
+ * @param {Array} sort - if multiple docs match, choose the first one in the specified sort order as the object to manipulate
+ * @param {Object} doc - the fields/vals to be updated
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the findAndModify method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.findAndModify = function findAndModify (query, sort, doc, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ sort = args.length ? args.shift() || [] : [];
+ doc = args.length ? args.shift() : null;
+ options = args.length ? args.shift() || {} : {};
+ var self = this;
+
+ var queryObject = {
+ 'findandmodify': this.collectionName
+ , 'query': query
+ , 'sort': utils.formattedOrderClause(sort)
+ };
+
+ queryObject.new = options.new ? 1 : 0;
+ queryObject.remove = options.remove ? 1 : 0;
+ queryObject.upsert = options.upsert ? 1 : 0;
+
+ if (options.fields) {
+ queryObject.fields = options.fields;
+ }
+
+ if (doc && !options.remove) {
+ queryObject.update = doc;
+ }
+
+ // Either use override on the function, or go back to default on either the collection
+ // level or db
+ if(options['serializeFunctions'] != null) {
+ options['serializeFunctions'] = options['serializeFunctions'];
+ } else {
+ options['serializeFunctions'] = this.serializeFunctions;
+ }
+
+ // Unpack the error options if any
+ var errorOptions = _getWriteConcern(this, options, callback);
+ // If we have j, w or something else do the getLast Error path
+ if(errorOptions != null
+ && typeof errorOptions == 'object'
+ && (errorOptions.w != 0 && errorOptions.w != 1 && errorOptions.safe != false)) {
+ // Commands to send
+ var commands = [];
+ // Add the find and modify command
+ commands.push(DbCommand.createDbCommand(this.db, queryObject, options));
+ // If we have safe defined we need to return both call results
+ var chainedCommands = errorOptions != null ? true : false;
+ // Add error command if we have one
+ if(chainedCommands) {
+ commands.push(DbCommand.createGetLastErrorCommand(errorOptions, this.db));
+ }
+
+ // Fire commands and
+ this.db._executeQueryCommand(commands, {read:false}, function(err, result) {
+ if(err != null) return callback(err);
+ result = result && result.documents;
+
+ if(result[0].err != null) {
+ return callback(utils.toError(result[0]), null);
+ }
+
+ // Workaround due to 1.8.X returning an error on no matching object
+ // while 2.0.X does not not, making 2.0.X behaviour standard
+ if(result[0].errmsg != null && !result[0].errmsg.match(eErrorMessages)) {
+ return callback(utils.toError(result[0]), null, result[0]);
+ }
+
+ return callback(null, result[0].value, result[0]);
+ });
+ } else {
+ // Only run command and rely on getLastError command
+ var command = DbCommand.createDbCommand(this.db, queryObject, options)
+ // Execute command
+ this.db._executeQueryCommand(command, {read:false}, function(err, result) {
+ if(err != null) return callback(err);
+
+ result = result && result.documents;
+
+ if(result[0].errmsg != null && !result[0].errmsg.match(eErrorMessages)) {
+ return callback(utils.toError(result[0]), null, result[0]);
+ }
+
+ // If we have an error return it
+ if(result[0].lastErrorObject && result[0].lastErrorObject.err != null) {
+ return callback(utils.toError(result[0].lastErrorObject), null);
+ }
+
+ return callback(null, result[0].value, result[0]);
+ });
+ }
+}
+
+/**
+ * Find and remove a document
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {Object} query query object to locate the object to modify
+ * @param {Array} sort - if multiple docs match, choose the first one in the specified sort order as the object to manipulate
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the findAndRemove method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.findAndRemove = function(query, sort, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ sort = args.length ? args.shift() || [] : [];
+ options = args.length ? args.shift() || {} : {};
+ // Add the remove option
+ options['remove'] = true;
+ // Execute the callback
+ this.findAndModify(query, sort, null, options, callback);
+}
+
+var testForFields = {
+ limit: 1, sort: 1, fields:1, skip: 1, hint: 1, explain: 1, snapshot: 1, timeout: 1, tailable: 1, tailableRetryInterval: 1
+ , numberOfRetries: 1, awaitdata: 1, exhaust: 1, batchSize: 1, returnKey: 1, maxScan: 1, min: 1, max: 1, showDiskLoc: 1
+ , comment: 1, raw: 1, readPreference: 1, partial: 1, read: 1, dbName: 1
+};
+
+/**
+ * Creates a cursor for a query that can be used to iterate over results from MongoDB
+ *
+ * Various argument possibilities
+ * - callback?
+ * - selector, callback?,
+ * - selector, fields, callback?
+ * - selector, options, callback?
+ * - selector, fields, options, callback?
+ * - selector, fields, skip, limit, callback?
+ * - selector, fields, skip, limit, timeout, callback?
+ *
+ * Options
+ * - **limit** {Number, default:0}, sets the limit of documents returned in the query.
+ * - **sort** {Array | Object}, set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc.
+ * - **fields** {Object}, the fields to return in the query. Object of fields to include or exclude (not both), {'a':1}
+ * - **skip** {Number, default:0}, set to skip N documents ahead in your query (useful for pagination).
+ * - **hint** {Object}, tell the query to use specific indexes in the query. Object of indexes to use, {'_id':1}
+ * - **explain** {Boolean, default:false}, explain the query instead of returning the data.
+ * - **snapshot** {Boolean, default:false}, snapshot query.
+ * - **timeout** {Boolean, default:false}, specify if the cursor can timeout.
+ * - **tailable** {Boolean, default:false}, specify if the cursor is tailable.
+ * - **tailableRetryInterval** {Number, default:100}, specify the miliseconds between getMores on tailable cursor.
+ * - **numberOfRetries** {Number, default:5}, specify the number of times to retry the tailable cursor.
+ * - **awaitdata** {Boolean, default:false} allow the cursor to wait for data, only applicable for tailable cursor.
+ * - **exhaust** {Boolean, default:false} have the server send all the documents at once as getMore packets, not recommended.
+ * - **batchSize** {Number, default:0}, set the batchSize for the getMoreCommand when iterating over the query results.
+ * - **returnKey** {Boolean, default:false}, only return the index key.
+ * - **maxScan** {Number}, Limit the number of items to scan.
+ * - **min** {Number}, Set index bounds.
+ * - **max** {Number}, Set index bounds.
+ * - **showDiskLoc** {Boolean, default:false}, Show disk location of results.
+ * - **comment** {String}, You can put a $comment field on a query to make looking in the profiler logs simpler.
+ * - **raw** {Boolean, default:false}, Return all BSON documents as Raw Buffer documents.
+ * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ * - **numberOfRetries** {Number, default:5}, if using awaidata specifies the number of times to retry on timeout.
+ * - **partial** {Boolean, default:false}, specify if the cursor should return partial results when querying against a sharded system
+ *
+ * @param {Object|ObjectID} query query object to locate the object to modify
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the find method or null if an error occured.
+ * @return {Cursor} returns a cursor to the query
+ * @api public
+ */
+Collection.prototype.find = function find () {
+ var options
+ , args = Array.prototype.slice.call(arguments, 0)
+ , has_callback = typeof args[args.length - 1] === 'function'
+ , has_weird_callback = typeof args[0] === 'function'
+ , callback = has_callback ? args.pop() : (has_weird_callback ? args.shift() : null)
+ , len = args.length
+ , selector = len >= 1 ? args[0] : {}
+ , fields = len >= 2 ? args[1] : undefined;
+
+ if(len === 1 && has_weird_callback) {
+ // backwards compat for callback?, options case
+ selector = {};
+ options = args[0];
+ }
+
+ if(len === 2 && !Array.isArray(fields)) {
+ var fieldKeys = Object.getOwnPropertyNames(fields);
+ var is_option = false;
+
+ for(var i = 0; i < fieldKeys.length; i++) {
+ if(testForFields[fieldKeys[i]] != null) {
+ is_option = true;
+ break;
+ }
+ }
+
+ if(is_option) {
+ options = fields;
+ fields = undefined;
+ } else {
+ options = {};
+ }
+ } else if(len === 2 && Array.isArray(fields) && !Array.isArray(fields[0])) {
+ var newFields = {};
+ // Rewrite the array
+ for(var i = 0; i < fields.length; i++) {
+ newFields[fields[i]] = 1;
+ }
+ // Set the fields
+ fields = newFields;
+ }
+
+ if(3 === len) {
+ options = args[2];
+ }
+
+ // Ensure selector is not null
+ selector = selector == null ? {} : selector;
+ // Validate correctness off the selector
+ var object = selector;
+ if(Buffer.isBuffer(object)) {
+ var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
+ if(object_size != object.length) {
+ var error = new Error("query selector raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
+ error.name = 'MongoError';
+ throw error;
+ }
+ }
+
+ // Validate correctness of the field selector
+ var object = fields;
+ if(Buffer.isBuffer(object)) {
+ var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
+ if(object_size != object.length) {
+ var error = new Error("query fields raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
+ error.name = 'MongoError';
+ throw error;
+ }
+ }
+
+ // Check special case where we are using an objectId
+ if(selector instanceof ObjectID || (selector != null && selector._bsontype == 'ObjectID')) {
+ selector = {_id:selector};
+ }
+
+ // If it's a serialized fields field we need to just let it through
+ // user be warned it better be good
+ if(options && options.fields && !(Buffer.isBuffer(options.fields))) {
+ fields = {};
+
+ if(Array.isArray(options.fields)) {
+ if(!options.fields.length) {
+ fields['_id'] = 1;
+ } else {
+ for (var i = 0, l = options.fields.length; i < l; i++) {
+ fields[options.fields[i]] = 1;
+ }
+ }
+ } else {
+ fields = options.fields;
+ }
+ }
+
+ if (!options) options = {};
+ options.skip = len > 3 ? args[2] : options.skip ? options.skip : 0;
+ options.limit = len > 3 ? args[3] : options.limit ? options.limit : 0;
+ options.raw = options.raw != null && typeof options.raw === 'boolean' ? options.raw : this.raw;
+ options.hint = options.hint != null ? normalizeHintField(options.hint) : this.internalHint;
+ options.timeout = len == 5 ? args[4] : typeof options.timeout === 'undefined' ? undefined : options.timeout;
+ // If we have overridden slaveOk otherwise use the default db setting
+ options.slaveOk = options.slaveOk != null ? options.slaveOk : this.db.slaveOk;
+
+ // Set option
+ var o = options;
+ // Support read/readPreference
+ if(o["read"] != null) o["readPreference"] = o["read"];
+ // Set the read preference
+ o.read = o["readPreference"] ? o.readPreference : this.readPreference;
+ // Adjust slave ok if read preference is secondary or secondary only
+ if(o.read == "secondary" || o.read == "secondaryOnly") options.slaveOk = true;
+
+ // callback for backward compatibility
+ if(callback) {
+ // TODO refactor Cursor args
+ callback(null, new Cursor(this.db, this, selector, fields, o));
+ } else {
+ return new Cursor(this.db, this, selector, fields, o);
+ }
+};
+
+/**
+ * Normalizes a `hint` argument.
+ *
+ * @param {String|Object|Array} hint
+ * @return {Object}
+ * @api private
+ */
+var normalizeHintField = function normalizeHintField(hint) {
+ var finalHint = null;
+
+ if(typeof hint == 'string') {
+ finalHint = hint;
+ } else if(Array.isArray(hint)) {
+ finalHint = {};
+
+ hint.forEach(function(param) {
+ finalHint[param] = 1;
+ });
+ } else if(hint != null && typeof hint == 'object') {
+ finalHint = {};
+ for (var name in hint) {
+ finalHint[name] = hint[name];
+ }
+ }
+
+ return finalHint;
+};
+
+/**
+ * Finds a single document based on the query
+ *
+ * Various argument possibilities
+ * - callback?
+ * - selector, callback?,
+ * - selector, fields, callback?
+ * - selector, options, callback?
+ * - selector, fields, options, callback?
+ * - selector, fields, skip, limit, callback?
+ * - selector, fields, skip, limit, timeout, callback?
+ *
+ * Options
+ * - **limit** {Number, default:0}, sets the limit of documents returned in the query.
+ * - **sort** {Array | Object}, set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc.
+ * - **fields** {Object}, the fields to return in the query. Object of fields to include or exclude (not both), {'a':1}
+ * - **skip** {Number, default:0}, set to skip N documents ahead in your query (useful for pagination).
+ * - **hint** {Object}, tell the query to use specific indexes in the query. Object of indexes to use, {'_id':1}
+ * - **explain** {Boolean, default:false}, explain the query instead of returning the data.
+ * - **snapshot** {Boolean, default:false}, snapshot query.
+ * - **timeout** {Boolean, default:false}, specify if the cursor can timeout.
+ * - **tailable** {Boolean, default:false}, specify if the cursor is tailable.
+ * - **batchSize** {Number, default:0}, set the batchSize for the getMoreCommand when iterating over the query results.
+ * - **returnKey** {Boolean, default:false}, only return the index key.
+ * - **maxScan** {Number}, Limit the number of items to scan.
+ * - **min** {Number}, Set index bounds.
+ * - **max** {Number}, Set index bounds.
+ * - **showDiskLoc** {Boolean, default:false}, Show disk location of results.
+ * - **comment** {String}, You can put a $comment field on a query to make looking in the profiler logs simpler.
+ * - **raw** {Boolean, default:false}, Return all BSON documents as Raw Buffer documents.
+ * - **readPreference** {String}, the preferred read preference (Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ * - **partial** {Boolean, default:false}, specify if the cursor should return partial results when querying against a sharded system
+ *
+ * @param {Object|ObjectID} query query object to locate the object to modify
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the findOne method or null if an error occured.
+ * @return {Cursor} returns a cursor to the query
+ * @api public
+ */
+Collection.prototype.findOne = function findOne () {
+ var self = this;
+ var args = Array.prototype.slice.call(arguments, 0);
+ var callback = args.pop();
+ var cursor = this.find.apply(this, args).limit(-1).batchSize(1);
+ // Return the item
+ cursor.nextObject(function(err, item) {
+ if(err != null) return callback(utils.toError(err), null);
+ callback(null, item);
+ });
+};
+
+/**
+ * Creates an index on the collection.
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **unique** {Boolean, default:false}, creates an unique index.
+ * - **sparse** {Boolean, default:false}, creates a sparse index.
+ * - **background** {Boolean, default:false}, creates the index in the background, yielding whenever possible.
+ * - **dropDups** {Boolean, default:false}, a unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
+ * - **min** {Number}, for geospatial indexes set the lower bound for the co-ordinates.
+ * - **max** {Number}, for geospatial indexes set the high bound for the co-ordinates.
+ * - **v** {Number}, specify the format version of the indexes.
+ * - **expireAfterSeconds** {Number}, allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
+ * - **name** {String}, override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {Object} fieldOrSpec fieldOrSpec that defines the index.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the createIndex method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.createIndex = function createIndex (fieldOrSpec, options, callback) {
+ // Clean up call
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+ options = typeof callback === 'function' ? options : callback;
+ options = options == null ? {} : options;
+
+ // Collect errorOptions
+ var errorOptions = _getWriteConcern(this, options, callback);
+ // Execute create index
+ this.db.createIndex(this.collectionName, fieldOrSpec, options, callback);
+};
+
+/**
+ * Ensures that an index exists, if it does not it creates it
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **unique** {Boolean, default:false}, creates an unique index.
+ * - **sparse** {Boolean, default:false}, creates a sparse index.
+ * - **background** {Boolean, default:false}, creates the index in the background, yielding whenever possible.
+ * - **dropDups** {Boolean, default:false}, a unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
+ * - **min** {Number}, for geospatial indexes set the lower bound for the co-ordinates.
+ * - **max** {Number}, for geospatial indexes set the high bound for the co-ordinates.
+ * - **v** {Number}, specify the format version of the indexes.
+ * - **expireAfterSeconds** {Number}, allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
+ * - **name** {String}, override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {Object} fieldOrSpec fieldOrSpec that defines the index.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the ensureIndex method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.ensureIndex = function ensureIndex (fieldOrSpec, options, callback) {
+ // Clean up call
+ if (typeof callback === 'undefined' && typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ if (options == null) {
+ options = {};
+ }
+
+ // Execute create index
+ this.db.ensureIndex(this.collectionName, fieldOrSpec, options, callback);
+};
+
+/**
+ * Retrieves this collections index info.
+ *
+ * Options
+ * - **full** {Boolean, default:false}, returns the full raw index information.
+ *
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the indexInformation method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.indexInformation = function indexInformation (options, callback) {
+ // Unpack calls
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+ // Call the index information
+ this.db.indexInformation(this.collectionName, options, callback);
+};
+
+/**
+ * Drops an index from this collection.
+ *
+ * @param {String} name
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the dropIndex method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.dropIndex = function dropIndex (name, callback) {
+ this.db.dropIndex(this.collectionName, name, callback);
+};
+
+/**
+ * Drops all indexes from this collection.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the dropAllIndexes method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.dropAllIndexes = function dropIndexes (callback) {
+ this.db.dropIndex(this.collectionName, '*', function (err, result) {
+ if(err != null) {
+ callback(err, false);
+ } else if(result.documents[0].errmsg == null) {
+ callback(null, true);
+ } else {
+ callback(new Error(result.documents[0].errmsg), false);
+ }
+ });
+};
+
+/**
+ * Drops all indexes from this collection.
+ *
+ * @deprecated
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the dropIndexes method or null if an error occured.
+ * @return {null}
+ * @api private
+ */
+Collection.prototype.dropIndexes = Collection.prototype.dropAllIndexes;
+
+/**
+ * Reindex all indexes on the collection
+ * Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the reIndex method or null if an error occured.
+ * @return {null}
+ * @api public
+**/
+Collection.prototype.reIndex = function(callback) {
+ this.db.reIndex(this.collectionName, callback);
+}
+
+/**
+ * Run Map Reduce across a collection. Be aware that the inline option for out will return an array of results not a collection.
+ *
+ * Options
+ * - **out** {Object}, sets the output target for the map reduce job. *{inline:1} | {replace:'collectionName'} | {merge:'collectionName'} | {reduce:'collectionName'}*
+ * - **query** {Object}, query filter object.
+ * - **sort** {Object}, sorts the input objects using this key. Useful for optimization, like sorting by the emit key for fewer reduces.
+ * - **limit** {Number}, number of objects to return from collection.
+ * - **keeptemp** {Boolean, default:false}, keep temporary data.
+ * - **finalize** {Function | String}, finalize function.
+ * - **scope** {Object}, can pass in variables that can be access from map/reduce/finalize.
+ * - **jsMode** {Boolean, default:false}, it is possible to make the execution stay in JS. Provided in MongoDB > 2.0.X.
+ * - **verbose** {Boolean, default:false}, provide statistics on job execution time.
+ * - **readPreference** {String, only for inline results}, the preferred read preference (Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ *
+ * @param {Function|String} map the mapping function.
+ * @param {Function|String} reduce the reduce function.
+ * @param {Objects} [options] options for the map reduce job.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the mapReduce method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.mapReduce = function mapReduce (map, reduce, options, callback) {
+ if ('function' === typeof options) callback = options, options = {};
+ // Out must allways be defined (make sure we don't break weirdly on pre 1.8+ servers)
+ if(null == options.out) {
+ throw new Error("the out option parameter must be defined, see mongodb docs for possible values");
+ }
+
+ if ('function' === typeof map) {
+ map = map.toString();
+ }
+
+ if ('function' === typeof reduce) {
+ reduce = reduce.toString();
+ }
+
+ if ('function' === typeof options.finalize) {
+ options.finalize = options.finalize.toString();
+ }
+
+ var mapCommandHash = {
+ mapreduce: this.collectionName
+ , map: map
+ , reduce: reduce
+ };
+
+ // Add any other options passed in
+ for (var name in options) {
+ if ('scope' == name) {
+ mapCommandHash[name] = processScope(options[name]);
+ } else {
+ mapCommandHash[name] = options[name];
+ }
+ }
+
+ // Set read preference if we set one
+ var readPreference = _getReadConcern(this, options);
+
+ // If we have a read preference and inline is not set as output fail hard
+ if((readPreference != false && readPreference != 'primary') && options['out'] != 'inline') {
+ throw new Error("a readPreference can only be provided when performing an inline mapReduce");
+ }
+
+ // self
+ var self = this;
+ var cmd = DbCommand.createDbCommand(this.db, mapCommandHash);
+
+ this.db._executeQueryCommand(cmd, {read:readPreference}, function (err, result) {
+ if (err) {
+ return callback(err);
+ }
+
+ //
+ if (1 != result.documents[0].ok || result.documents[0].err || result.documents[0].errmsg) {
+ return callback(utils.toError(result.documents[0]));
+ }
+
+ // Create statistics value
+ var stats = {};
+ if(result.documents[0].timeMillis) stats['processtime'] = result.documents[0].timeMillis;
+ if(result.documents[0].counts) stats['counts'] = result.documents[0].counts;
+ if(result.documents[0].timing) stats['timing'] = result.documents[0].timing;
+
+ // invoked with inline?
+ if(result.documents[0].results) {
+ return callback(null, result.documents[0].results, stats);
+ }
+
+ // The returned collection
+ var collection = null;
+
+ // If we have an object it's a different db
+ if(result.documents[0].result != null && typeof result.documents[0].result == 'object') {
+ var doc = result.documents[0].result;
+ collection = self.db.db(doc.db).collection(doc.collection);
+ } else {
+ // Create a collection object that wraps the result collection
+ collection = self.db.collection(result.documents[0].result)
+ }
+
+ // If we wish for no verbosity
+ if(options['verbose'] == null || !options['verbose']) {
+ return callback(err, collection);
+ }
+
+ // Return stats as third set of values
+ callback(err, collection, stats);
+ });
+};
+
+/**
+ * Functions that are passed as scope args must
+ * be converted to Code instances.
+ * @ignore
+ */
+function processScope (scope) {
+ if (!utils.isObject(scope)) {
+ return scope;
+ }
+
+ var keys = Object.keys(scope);
+ var i = keys.length;
+ var key;
+
+ while (i--) {
+ key = keys[i];
+ if ('function' == typeof scope[key]) {
+ scope[key] = new Code(String(scope[key]));
+ }
+ }
+
+ return scope;
+}
+
+/**
+ * Group function helper
+ * @ignore
+ */
+var groupFunction = function () {
+ var c = db[ns].find(condition);
+ var map = new Map();
+ var reduce_function = reduce;
+
+ while (c.hasNext()) {
+ var obj = c.next();
+ var key = {};
+
+ for (var i = 0, len = keys.length; i < len; ++i) {
+ var k = keys[i];
+ key[k] = obj[k];
+ }
+
+ var aggObj = map.get(key);
+
+ if (aggObj == null) {
+ var newObj = Object.extend({}, key);
+ aggObj = Object.extend(newObj, initial);
+ map.put(key, aggObj);
+ }
+
+ reduce_function(obj, aggObj);
+ }
+
+ return { "result": map.values() };
+}.toString();
+
+/**
+ * Run a group command across a collection
+ *
+ * Options
+ * - **readPreference** {String}, the preferred read preference (Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ *
+ * @param {Object|Array|Function|Code} keys an object, array or function expressing the keys to group by.
+ * @param {Object} condition an optional condition that must be true for a row to be considered.
+ * @param {Object} initial initial value of the aggregation counter object.
+ * @param {Function|Code} reduce the reduce function aggregates (reduces) the objects iterated
+ * @param {Function|Code} finalize an optional function to be run on each item in the result set just before the item is returned.
+ * @param {Boolean} command specify if you wish to run using the internal group command or using eval, default is true.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the group method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.group = function group(keys, condition, initial, reduce, finalize, command, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 3);
+ callback = args.pop();
+ // Fetch all commands
+ reduce = args.length ? args.shift() : null;
+ finalize = args.length ? args.shift() : null;
+ command = args.length ? args.shift() : null;
+ options = args.length ? args.shift() || {} : {};
+
+ // Make sure we are backward compatible
+ if(!(typeof finalize == 'function')) {
+ command = finalize;
+ finalize = null;
+ }
+
+ if (!Array.isArray(keys) && keys instanceof Object && typeof(keys) !== 'function' && !(keys instanceof Code)) {
+ keys = Object.keys(keys);
+ }
+
+ if(typeof reduce === 'function') {
+ reduce = reduce.toString();
+ }
+
+ if(typeof finalize === 'function') {
+ finalize = finalize.toString();
+ }
+
+ // Set up the command as default
+ command = command == null ? true : command;
+
+ // Execute using the command
+ if(command) {
+ var reduceFunction = reduce instanceof Code
+ ? reduce
+ : new Code(reduce);
+
+ var selector = {
+ group: {
+ 'ns': this.collectionName
+ , '$reduce': reduceFunction
+ , 'cond': condition
+ , 'initial': initial
+ , 'out': "inline"
+ }
+ };
+
+ // if finalize is defined
+ if(finalize != null) selector.group['finalize'] = finalize;
+ // Set up group selector
+ if ('function' === typeof keys || keys instanceof Code) {
+ selector.group.$keyf = keys instanceof Code
+ ? keys
+ : new Code(keys);
+ } else {
+ var hash = {};
+ keys.forEach(function (key) {
+ hash[key] = 1;
+ });
+ selector.group.key = hash;
+ }
+
+ var cmd = DbCommand.createDbSlaveOkCommand(this.db, selector);
+ // Set read preference if we set one
+ var readPreference = _getReadConcern(this, options);
+
+ this.db._executeQueryCommand(cmd, {read:readPreference}, function (err, result) {
+ if(err != null) return callback(err);
+
+ var document = result.documents[0];
+ if (null == document.retval) {
+ return callback(new Error("group command failed: " + document.errmsg));
+ }
+
+ callback(null, document.retval);
+ });
+
+ } else {
+ // Create execution scope
+ var scope = reduce != null && reduce instanceof Code
+ ? reduce.scope
+ : {};
+
+ scope.ns = this.collectionName;
+ scope.keys = keys;
+ scope.condition = condition;
+ scope.initial = initial;
+
+ // Pass in the function text to execute within mongodb.
+ var groupfn = groupFunction.replace(/ reduce;/, reduce.toString() + ';');
+
+ this.db.eval(new Code(groupfn, scope), function (err, results) {
+ if (err) return callback(err, null);
+ callback(null, results.result || results);
+ });
+ }
+};
+
+/**
+ * Returns the options of the collection.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the options method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.options = function options(callback) {
+ this.db.collectionsInfo(this.collectionName, function (err, cursor) {
+ if (err) return callback(err);
+ cursor.nextObject(function (err, document) {
+ callback(err, document && document.options || null);
+ });
+ });
+};
+
+/**
+ * Returns if the collection is a capped collection
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the isCapped method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.isCapped = function isCapped(callback) {
+ this.options(function(err, document) {
+ if(err != null) {
+ callback(err);
+ } else {
+ callback(null, document && document.capped);
+ }
+ });
+};
+
+/**
+ * Checks if one or more indexes exist on the collection
+ *
+ * @param {String|Array} indexNames check if one or more indexes exist on the collection.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the indexExists method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.indexExists = function indexExists(indexes, callback) {
+ this.indexInformation(function(err, indexInformation) {
+ // If we have an error return
+ if(err != null) return callback(err, null);
+ // Let's check for the index names
+ if(Array.isArray(indexes)) {
+ for(var i = 0; i < indexes.length; i++) {
+ if(indexInformation[indexes[i]] == null) {
+ return callback(null, false);
+ }
+ }
+
+ // All keys found return true
+ return callback(null, true);
+ } else {
+ return callback(null, indexInformation[indexes] != null);
+ }
+ });
+}
+
+/**
+ * Execute the geoNear command to search for items in the collection
+ *
+ * Options
+ * - **num** {Number}, max number of results to return.
+ * - **maxDistance** {Number}, include results up to maxDistance from the point.
+ * - **distanceMultiplier** {Number}, include a value to multiply the distances with allowing for range conversions.
+ * - **query** {Object}, filter the results by a query.
+ * - **spherical** {Boolean, default:false}, perform query using a spherical model.
+ * - **uniqueDocs** {Boolean, default:false}, the closest location in a document to the center of the search region will always be returned MongoDB > 2.X.
+ * - **includeLocs** {Boolean, default:false}, include the location data fields in the top level of the results MongoDB > 2.X.
+ * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ *
+ * @param {Number} x point to search on the x axis, ensure the indexes are ordered in the same order.
+ * @param {Number} y point to search on the y axis, ensure the indexes are ordered in the same order.
+ * @param {Objects} [options] options for the map reduce job.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the geoNear method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.geoNear = function geoNear(x, y, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = args.pop();
+ // Fetch all commands
+ options = args.length ? args.shift() || {} : {};
+
+ // Build command object
+ var commandObject = {
+ geoNear:this.collectionName,
+ near: [x, y]
+ }
+
+ // Decorate object if any with known properties
+ if(options['num'] != null) commandObject['num'] = options['num'];
+ if(options['maxDistance'] != null) commandObject['maxDistance'] = options['maxDistance'];
+ if(options['distanceMultiplier'] != null) commandObject['distanceMultiplier'] = options['distanceMultiplier'];
+ if(options['query'] != null) commandObject['query'] = options['query'];
+ if(options['spherical'] != null) commandObject['spherical'] = options['spherical'];
+ if(options['uniqueDocs'] != null) commandObject['uniqueDocs'] = options['uniqueDocs'];
+ if(options['includeLocs'] != null) commandObject['includeLocs'] = options['includeLocs'];
+
+ // Ensure we have the right read preference inheritance
+ options.readPreference = _getReadConcern(this, options);
+
+ // Execute the command
+ this.db.command(commandObject, options, callback);
+}
+
+/**
+ * Execute a geo search using a geo haystack index on a collection.
+ *
+ * Options
+ * - **maxDistance** {Number}, include results up to maxDistance from the point.
+ * - **search** {Object}, filter the results by a query.
+ * - **limit** {Number}, max number of results to return.
+ * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ *
+ * @param {Number} x point to search on the x axis, ensure the indexes are ordered in the same order.
+ * @param {Number} y point to search on the y axis, ensure the indexes are ordered in the same order.
+ * @param {Objects} [options] options for the map reduce job.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the geoHaystackSearch method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.geoHaystackSearch = function geoHaystackSearch(x, y, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = args.pop();
+ // Fetch all commands
+ options = args.length ? args.shift() || {} : {};
+
+ // Build command object
+ var commandObject = {
+ geoSearch:this.collectionName,
+ near: [x, y]
+ }
+
+ // Decorate object if any with known properties
+ if(options['maxDistance'] != null) commandObject['maxDistance'] = options['maxDistance'];
+ if(options['query'] != null) commandObject['search'] = options['query'];
+ if(options['search'] != null) commandObject['search'] = options['search'];
+ if(options['limit'] != null) commandObject['limit'] = options['limit'];
+
+ // Ensure we have the right read preference inheritance
+ options.readPreference = _getReadConcern(this, options);
+
+ // Execute the command
+ this.db.command(commandObject, options, callback);
+}
+
+/**
+ * Retrieve all the indexes on the collection.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the indexes method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.indexes = function indexes(callback) {
+ // Return all the index information
+ this.db.indexInformation(this.collectionName, {full:true}, callback);
+}
+
+/**
+ * Execute an aggregation framework pipeline against the collection, needs MongoDB >= 2.1
+ *
+ * Options
+ * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ *
+ * @param {Array} array containing all the aggregation framework commands for the execution.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the aggregate method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.aggregate = function(pipeline, options, callback) {
+ // * - **explain** {Boolean}, return the query plan for the aggregation pipeline instead of the results. 2.3, 2.4
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ var self = this;
+
+ // If we have any of the supported options in the options object
+ var opts = args[args.length - 1];
+ options = opts.readPreference || opts.explain ? args.pop() : {}
+
+ // Convert operations to an array
+ if(!Array.isArray(args[0])) {
+ pipeline = [];
+ // Push all the operations to the pipeline
+ for(var i = 0; i < args.length; i++) pipeline.push(args[i]);
+ }
+
+ // Build the command
+ var command = { aggregate : this.collectionName, pipeline : pipeline};
+
+ // Ensure we have the right read preference inheritance
+ options.readPreference = _getReadConcern(this, options);
+
+ // Execute the command
+ this.db.command(command, options, function(err, result) {
+ if(err) {
+ callback(err);
+ } else if(result['err'] || result['errmsg']) {
+ callback(utils.toError(result));
+ } else if(typeof result == 'object' && result['serverPipeline']) {
+ callback(null, result);
+ } else {
+ callback(null, result.result);
+ }
+ });
+}
+
+/**
+ * Get all the collection statistics.
+ *
+ * Options
+ * - **scale** {Number}, divide the returned sizes by scale value.
+ * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ *
+ * @param {Objects} [options] options for the stats command.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the stats method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Collection.prototype.stats = function stats(options, callback) {
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ // Fetch all commands
+ options = args.length ? args.shift() || {} : {};
+
+ // Build command object
+ var commandObject = {
+ collStats:this.collectionName,
+ }
+
+ // Check if we have the scale value
+ if(options['scale'] != null) commandObject['scale'] = options['scale'];
+
+ // Ensure we have the right read preference inheritance
+ options.readPreference = _getReadConcern(this, options);
+
+ // Execute the command
+ this.db.command(commandObject, options, callback);
+}
+
+/**
+ * @ignore
+ */
+Object.defineProperty(Collection.prototype, "hint", {
+ enumerable: true
+ , get: function () {
+ return this.internalHint;
+ }
+ , set: function (v) {
+ this.internalHint = normalizeHintField(v);
+ }
+});
+
+var _getReadConcern = function(self, options) {
+ if(options.readPreference) return options.readPreference;
+ if(self.readPreference) return self.readPreference;
+ if(self.db.readPreference) return self.readPreference;
+ return 'primary';
+}
+
+/**
+ * @ignore
+ */
+var _hasWriteConcern = function(errorOptions) {
+ return errorOptions == true
+ || errorOptions.w > 0
+ || errorOptions.w == 'majority'
+ || errorOptions.j == true
+ || errorOptions.journal == true
+ || errorOptions.fsync == true
+}
+
+/**
+ * @ignore
+ */
+var _setWriteConcernHash = function(options) {
+ var finalOptions = {};
+ if(options.w != null) finalOptions.w = options.w;
+ if(options.journal == true) finalOptions.j = options.journal;
+ if(options.j == true) finalOptions.j = options.j;
+ if(options.fsync == true) finalOptions.fsync = options.fsync;
+ if(options.wtimeout != null) finalOptions.wtimeout = options.wtimeout;
+ return finalOptions;
+}
+
+/**
+ * @ignore
+ */
+var _getWriteConcern = function(self, options, callback) {
+ // Final options
+ var finalOptions = {w:1};
+ // Local options verification
+ if(options.w != null || typeof options.j == 'boolean' || typeof options.journal == 'boolean' || typeof options.fsync == 'boolean') {
+ finalOptions = _setWriteConcernHash(options);
+ } else if(typeof options.safe == "boolean") {
+ finalOptions = {w: (options.safe ? 1 : 0)};
+ } else if(options.safe != null && typeof options.safe == 'object') {
+ finalOptions = _setWriteConcernHash(options.safe);
+ } else if(self.opts.w != null || typeof self.opts.j == 'boolean' || typeof self.opts.journal == 'boolean' || typeof self.opts.fsync == 'boolean') {
+ finalOptions = _setWriteConcernHash(self.opts);
+ } else if(typeof self.opts.safe == "boolean") {
+ finalOptions = {w: (self.opts.safe ? 1 : 0)};
+ } else if(self.db.safe.w != null || typeof self.db.safe.j == 'boolean' || typeof self.db.safe.journal == 'boolean' || typeof self.db.safe.fsync == 'boolean') {
+ finalOptions = _setWriteConcernHash(self.db.safe);
+ } else if(self.db.options.w != null || typeof self.db.options.j == 'boolean' || typeof self.db.options.journal == 'boolean' || typeof self.db.options.fsync == 'boolean') {
+ finalOptions = _setWriteConcernHash(self.db.options);
+ } else if(typeof self.db.safe == "boolean") {
+ finalOptions = {w: (self.db.safe ? 1 : 0)};
+ }
+
+ // Ensure we don't have an invalid combination of write concerns
+ if(finalOptions.w < 1
+ && (finalOptions.journal == true || finalOptions.j == true || finalOptions.fsync == true)) throw new Error("No acknowlegement using w < 1 cannot be combined with journal:true or fsync:true");
+
+ // Return the options
+ return finalOptions;
+}
+
+/**
+ * Expose.
+ */
+exports.Collection = Collection;
diff --git a/node_modules/mongodb/lib/mongodb/commands/base_command.js b/node_modules/mongodb/lib/mongodb/commands/base_command.js
new file mode 100644
index 0000000..9558582
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/commands/base_command.js
@@ -0,0 +1,29 @@
+/**
+ Base object used for common functionality
+**/
+var BaseCommand = exports.BaseCommand = function BaseCommand() {
+};
+
+var id = 1;
+BaseCommand.prototype.getRequestId = function getRequestId() {
+ if (!this.requestId) this.requestId = id++;
+ return this.requestId;
+};
+
+BaseCommand.prototype.setMongosReadPreference = function setMongosReadPreference(readPreference, tags) {}
+
+BaseCommand.prototype.updateRequestId = function() {
+ this.requestId = id++;
+ return this.requestId;
+};
+
+// OpCodes
+BaseCommand.OP_REPLY = 1;
+BaseCommand.OP_MSG = 1000;
+BaseCommand.OP_UPDATE = 2001;
+BaseCommand.OP_INSERT = 2002;
+BaseCommand.OP_GET_BY_OID = 2003;
+BaseCommand.OP_QUERY = 2004;
+BaseCommand.OP_GET_MORE = 2005;
+BaseCommand.OP_DELETE = 2006;
+BaseCommand.OP_KILL_CURSORS = 2007;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/commands/db_command.js b/node_modules/mongodb/lib/mongodb/commands/db_command.js
new file mode 100644
index 0000000..f8751b5
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/commands/db_command.js
@@ -0,0 +1,241 @@
+var QueryCommand = require('./query_command').QueryCommand,
+ InsertCommand = require('./insert_command').InsertCommand,
+ inherits = require('util').inherits,
+ utils = require('../utils'),
+ crypto = require('crypto');
+
+/**
+ Db Command
+**/
+var DbCommand = exports.DbCommand = function(dbInstance, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector, options) {
+ QueryCommand.call(this);
+ this.collectionName = collectionName;
+ this.queryOptions = queryOptions;
+ this.numberToSkip = numberToSkip;
+ this.numberToReturn = numberToReturn;
+ this.query = query;
+ this.returnFieldSelector = returnFieldSelector;
+ this.db = dbInstance;
+
+ // Make sure we don't get a null exception
+ options = options == null ? {} : options;
+ // Let us defined on a command basis if we want functions to be serialized or not
+ if(options['serializeFunctions'] != null && options['serializeFunctions']) {
+ this.serializeFunctions = true;
+ }
+};
+
+inherits(DbCommand, QueryCommand);
+
+// Constants
+DbCommand.SYSTEM_NAMESPACE_COLLECTION = "system.namespaces";
+DbCommand.SYSTEM_INDEX_COLLECTION = "system.indexes";
+DbCommand.SYSTEM_PROFILE_COLLECTION = "system.profile";
+DbCommand.SYSTEM_USER_COLLECTION = "system.users";
+DbCommand.SYSTEM_COMMAND_COLLECTION = "$cmd";
+DbCommand.SYSTEM_JS_COLLECTION = "system.js";
+
+// New commands
+DbCommand.NcreateIsMasterCommand = function(db, databaseName) {
+ return new DbCommand(db, databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null);
+};
+
+// Provide constructors for different db commands
+DbCommand.createIsMasterCommand = function(db) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null);
+};
+
+DbCommand.createCollectionInfoCommand = function(db, selector) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_NAMESPACE_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, 0, selector, null);
+};
+
+DbCommand.createGetNonceCommand = function(db, options) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getnonce':1}, null);
+};
+
+DbCommand.createAuthenticationCommand = function(db, username, password, nonce, authdb) {
+ // Use node md5 generator
+ var md5 = crypto.createHash('md5');
+ // Generate keys used for authentication
+ md5.update(username + ":mongo:" + password);
+ var hash_password = md5.digest('hex');
+ // Final key
+ md5 = crypto.createHash('md5');
+ md5.update(nonce + username + hash_password);
+ var key = md5.digest('hex');
+ // Creat selector
+ var selector = {'authenticate':1, 'user':username, 'nonce':nonce, 'key':key};
+ // Create db command
+ return new DbCommand(db, authdb + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NONE, 0, -1, selector, null);
+};
+
+DbCommand.createLogoutCommand = function(db) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'logout':1}, null);
+};
+
+DbCommand.createCreateCollectionCommand = function(db, collectionName, options) {
+ var selector = {'create':collectionName};
+ // Modify the options to ensure correct behaviour
+ for(var name in options) {
+ if(options[name] != null && options[name].constructor != Function) selector[name] = options[name];
+ }
+ // Execute the command
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, selector, null);
+};
+
+DbCommand.createDropCollectionCommand = function(db, collectionName) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'drop':collectionName}, null);
+};
+
+DbCommand.createRenameCollectionCommand = function(db, fromCollectionName, toCollectionName, options) {
+ var renameCollection = db.databaseName + "." + fromCollectionName;
+ var toCollection = db.databaseName + "." + toCollectionName;
+ var dropTarget = options && options.dropTarget ? options.dropTarget : false;
+ return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'renameCollection':renameCollection, 'to':toCollection, 'dropTarget':dropTarget}, null);
+};
+
+DbCommand.createGetLastErrorCommand = function(options, db) {
+
+ if (typeof db === 'undefined') {
+ db = options;
+ options = {};
+ }
+ // Final command
+ var command = {'getlasterror':1};
+ // If we have an options Object let's merge in the fields (fsync/wtimeout/w)
+ if('object' === typeof options) {
+ for(var name in options) {
+ command[name] = options[name]
+ }
+ }
+
+ // Special case for w == 1, remove the w
+ if(1 == command.w) {
+ delete command.w;
+ }
+
+ // Execute command
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command, null);
+};
+
+DbCommand.createGetLastStatusCommand = DbCommand.createGetLastErrorCommand;
+
+DbCommand.createGetPreviousErrorsCommand = function(db) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getpreverror':1}, null);
+};
+
+DbCommand.createResetErrorHistoryCommand = function(db) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reseterror':1}, null);
+};
+
+DbCommand.createCreateIndexCommand = function(db, collectionName, fieldOrSpec, options) {
+ var fieldHash = {};
+ var indexes = [];
+ var keys;
+
+ // Get all the fields accordingly
+ if('string' == typeof fieldOrSpec) {
+ // 'type'
+ indexes.push(fieldOrSpec + '_' + 1);
+ fieldHash[fieldOrSpec] = 1;
+
+ } else if(utils.isArray(fieldOrSpec)) {
+
+ fieldOrSpec.forEach(function(f) {
+ if('string' == typeof f) {
+ // [{location:'2d'}, 'type']
+ indexes.push(f + '_' + 1);
+ fieldHash[f] = 1;
+ } else if(utils.isArray(f)) {
+ // [['location', '2d'],['type', 1]]
+ indexes.push(f[0] + '_' + (f[1] || 1));
+ fieldHash[f[0]] = f[1] || 1;
+ } else if(utils.isObject(f)) {
+ // [{location:'2d'}, {type:1}]
+ keys = Object.keys(f);
+ keys.forEach(function(k) {
+ indexes.push(k + '_' + f[k]);
+ fieldHash[k] = f[k];
+ });
+ } else {
+ // undefined (ignore)
+ }
+ });
+
+ } else if(utils.isObject(fieldOrSpec)) {
+ // {location:'2d', type:1}
+ keys = Object.keys(fieldOrSpec);
+ keys.forEach(function(key) {
+ indexes.push(key + '_' + fieldOrSpec[key]);
+ fieldHash[key] = fieldOrSpec[key];
+ });
+ }
+
+ // Generate the index name
+ var indexName = typeof options.name == 'string'
+ ? options.name
+ : indexes.join("_");
+
+ var selector = {
+ 'ns': db.databaseName + "." + collectionName,
+ 'key': fieldHash,
+ 'name': indexName
+ }
+
+ // Ensure we have a correct finalUnique
+ var finalUnique = options == null || 'object' === typeof options
+ ? false
+ : options;
+
+ // Set up options
+ options = options == null || typeof options == 'boolean'
+ ? {}
+ : options;
+
+ // Add all the options
+ var keys = Object.keys(options);
+ for(var i = 0; i < keys.length; i++) {
+ selector[keys[i]] = options[keys[i]];
+ }
+
+ if(selector['unique'] == null)
+ selector['unique'] = finalUnique;
+
+ var name = db.databaseName + "." + DbCommand.SYSTEM_INDEX_COLLECTION;
+ var cmd = new InsertCommand(db, name, false);
+ return cmd.add(selector);
+};
+
+DbCommand.logoutCommand = function(db, command_hash, options) {
+ var dbName = options != null && options['authdb'] != null ? options['authdb'] : db.databaseName;
+ return new DbCommand(db, dbName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null);
+}
+
+DbCommand.createDropIndexCommand = function(db, collectionName, indexName) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'deleteIndexes':collectionName, 'index':indexName}, null);
+};
+
+DbCommand.createReIndexCommand = function(db, collectionName) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reIndex':collectionName}, null);
+};
+
+DbCommand.createDropDatabaseCommand = function(db) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'dropDatabase':1}, null);
+};
+
+DbCommand.createDbCommand = function(db, command_hash, options, auth_db) {
+ var db_name = (auth_db ? auth_db : db.databaseName) + "." + DbCommand.SYSTEM_COMMAND_COLLECTION;
+ return new DbCommand(db, db_name, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null, options);
+};
+
+DbCommand.createAdminDbCommand = function(db, command_hash) {
+ return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null);
+};
+
+DbCommand.createAdminDbCommandSlaveOk = function(db, command_hash) {
+ return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT | QueryCommand.OPTS_SLAVE, 0, -1, command_hash, null);
+};
+
+DbCommand.createDbSlaveOkCommand = function(db, command_hash, options) {
+ return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT | QueryCommand.OPTS_SLAVE, 0, -1, command_hash, null, options);
+};
diff --git a/node_modules/mongodb/lib/mongodb/commands/delete_command.js b/node_modules/mongodb/lib/mongodb/commands/delete_command.js
new file mode 100644
index 0000000..e6ae20a
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/commands/delete_command.js
@@ -0,0 +1,114 @@
+var BaseCommand = require('./base_command').BaseCommand,
+ inherits = require('util').inherits;
+
+/**
+ Insert Document Command
+**/
+var DeleteCommand = exports.DeleteCommand = function(db, collectionName, selector, flags) {
+ BaseCommand.call(this);
+
+ // Validate correctness off the selector
+ var object = selector;
+ if(Buffer.isBuffer(object)) {
+ var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
+ if(object_size != object.length) {
+ var error = new Error("delete raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
+ error.name = 'MongoError';
+ throw error;
+ }
+ }
+
+ this.flags = flags;
+ this.collectionName = collectionName;
+ this.selector = selector;
+ this.db = db;
+};
+
+inherits(DeleteCommand, BaseCommand);
+
+DeleteCommand.OP_DELETE = 2006;
+
+/*
+struct {
+ MsgHeader header; // standard message header
+ int32 ZERO; // 0 - reserved for future use
+ cstring fullCollectionName; // "dbname.collectionname"
+ int32 ZERO; // 0 - reserved for future use
+ mongo.BSON selector; // query object. See below for details.
+}
+*/
+DeleteCommand.prototype.toBinary = function() {
+ // Calculate total length of the document
+ var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson.calculateObjectSize(this.selector, false, true) + (4 * 4);
+ // Let's build the single pass buffer command
+ var _index = 0;
+ var _command = new Buffer(totalLengthOfCommand);
+ // Write the header information to the buffer
+ _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
+ _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
+ _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
+ _command[_index] = totalLengthOfCommand & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write the request ID
+ _command[_index + 3] = (this.requestId >> 24) & 0xff;
+ _command[_index + 2] = (this.requestId >> 16) & 0xff;
+ _command[_index + 1] = (this.requestId >> 8) & 0xff;
+ _command[_index] = this.requestId & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write zero
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ // Write the op_code for the command
+ _command[_index + 3] = (DeleteCommand.OP_DELETE >> 24) & 0xff;
+ _command[_index + 2] = (DeleteCommand.OP_DELETE >> 16) & 0xff;
+ _command[_index + 1] = (DeleteCommand.OP_DELETE >> 8) & 0xff;
+ _command[_index] = DeleteCommand.OP_DELETE & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ // Write zero
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+
+ // Write the collection name to the command
+ _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
+ _command[_index - 1] = 0;
+
+ // Write the flags
+ _command[_index + 3] = (this.flags >> 24) & 0xff;
+ _command[_index + 2] = (this.flags >> 16) & 0xff;
+ _command[_index + 1] = (this.flags >> 8) & 0xff;
+ _command[_index] = this.flags & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ // Document binary length
+ var documentLength = 0
+
+ // Serialize the selector
+ // If we are passing a raw buffer, do minimal validation
+ if(Buffer.isBuffer(this.selector)) {
+ documentLength = this.selector.length;
+ // Copy the data into the current buffer
+ this.selector.copy(_command, _index);
+ } else {
+ documentLength = this.db.bson.serializeWithBufferAndIndex(this.selector, this.checkKeys, _command, _index) - _index + 1;
+ }
+
+ // Write the length to the document
+ _command[_index + 3] = (documentLength >> 24) & 0xff;
+ _command[_index + 2] = (documentLength >> 16) & 0xff;
+ _command[_index + 1] = (documentLength >> 8) & 0xff;
+ _command[_index] = documentLength & 0xff;
+ // Update index in buffer
+ _index = _index + documentLength;
+ // Add terminating 0 for the object
+ _command[_index - 1] = 0;
+ return _command;
+};
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/commands/get_more_command.js b/node_modules/mongodb/lib/mongodb/commands/get_more_command.js
new file mode 100644
index 0000000..d3aac02
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/commands/get_more_command.js
@@ -0,0 +1,83 @@
+var BaseCommand = require('./base_command').BaseCommand,
+ inherits = require('util').inherits,
+ binaryutils = require('../utils');
+
+/**
+ Get More Document Command
+**/
+var GetMoreCommand = exports.GetMoreCommand = function(db, collectionName, numberToReturn, cursorId) {
+ BaseCommand.call(this);
+
+ this.collectionName = collectionName;
+ this.numberToReturn = numberToReturn;
+ this.cursorId = cursorId;
+ this.db = db;
+};
+
+inherits(GetMoreCommand, BaseCommand);
+
+GetMoreCommand.OP_GET_MORE = 2005;
+
+GetMoreCommand.prototype.toBinary = function() {
+ // Calculate total length of the document
+ var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 8 + (4 * 4);
+ // Let's build the single pass buffer command
+ var _index = 0;
+ var _command = new Buffer(totalLengthOfCommand);
+ // Write the header information to the buffer
+ _command[_index++] = totalLengthOfCommand & 0xff;
+ _command[_index++] = (totalLengthOfCommand >> 8) & 0xff;
+ _command[_index++] = (totalLengthOfCommand >> 16) & 0xff;
+ _command[_index++] = (totalLengthOfCommand >> 24) & 0xff;
+
+ // Write the request ID
+ _command[_index++] = this.requestId & 0xff;
+ _command[_index++] = (this.requestId >> 8) & 0xff;
+ _command[_index++] = (this.requestId >> 16) & 0xff;
+ _command[_index++] = (this.requestId >> 24) & 0xff;
+
+ // Write zero
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+
+ // Write the op_code for the command
+ _command[_index++] = GetMoreCommand.OP_GET_MORE & 0xff;
+ _command[_index++] = (GetMoreCommand.OP_GET_MORE >> 8) & 0xff;
+ _command[_index++] = (GetMoreCommand.OP_GET_MORE >> 16) & 0xff;
+ _command[_index++] = (GetMoreCommand.OP_GET_MORE >> 24) & 0xff;
+
+ // Write zero
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+
+ // Write the collection name to the command
+ _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
+ _command[_index - 1] = 0;
+
+ // Number of documents to return
+ _command[_index++] = this.numberToReturn & 0xff;
+ _command[_index++] = (this.numberToReturn >> 8) & 0xff;
+ _command[_index++] = (this.numberToReturn >> 16) & 0xff;
+ _command[_index++] = (this.numberToReturn >> 24) & 0xff;
+
+ // Encode the cursor id
+ var low_bits = this.cursorId.getLowBits();
+ // Encode low bits
+ _command[_index++] = low_bits & 0xff;
+ _command[_index++] = (low_bits >> 8) & 0xff;
+ _command[_index++] = (low_bits >> 16) & 0xff;
+ _command[_index++] = (low_bits >> 24) & 0xff;
+
+ var high_bits = this.cursorId.getHighBits();
+ // Encode high bits
+ _command[_index++] = high_bits & 0xff;
+ _command[_index++] = (high_bits >> 8) & 0xff;
+ _command[_index++] = (high_bits >> 16) & 0xff;
+ _command[_index++] = (high_bits >> 24) & 0xff;
+ // Return command
+ return _command;
+};
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/commands/insert_command.js b/node_modules/mongodb/lib/mongodb/commands/insert_command.js
new file mode 100644
index 0000000..d6a2100
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/commands/insert_command.js
@@ -0,0 +1,147 @@
+var BaseCommand = require('./base_command').BaseCommand,
+ inherits = require('util').inherits;
+
+/**
+ Insert Document Command
+**/
+var InsertCommand = exports.InsertCommand = function(db, collectionName, checkKeys, options) {
+ BaseCommand.call(this);
+
+ this.collectionName = collectionName;
+ this.documents = [];
+ this.checkKeys = checkKeys == null ? true : checkKeys;
+ this.db = db;
+ this.flags = 0;
+ this.serializeFunctions = false;
+
+ // Ensure valid options hash
+ options = options == null ? {} : options;
+
+ // Check if we have keepGoing set -> set flag if it's the case
+ if(options['keepGoing'] != null && options['keepGoing']) {
+ // This will finish inserting all non-index violating documents even if it returns an error
+ this.flags = 1;
+ }
+
+ // Check if we have keepGoing set -> set flag if it's the case
+ if(options['continueOnError'] != null && options['continueOnError']) {
+ // This will finish inserting all non-index violating documents even if it returns an error
+ this.flags = 1;
+ }
+
+ // Let us defined on a command basis if we want functions to be serialized or not
+ if(options['serializeFunctions'] != null && options['serializeFunctions']) {
+ this.serializeFunctions = true;
+ }
+};
+
+inherits(InsertCommand, BaseCommand);
+
+// OpCodes
+InsertCommand.OP_INSERT = 2002;
+
+InsertCommand.prototype.add = function(document) {
+ if(Buffer.isBuffer(document)) {
+ var object_size = document[0] | document[1] << 8 | document[2] << 16 | document[3] << 24;
+ if(object_size != document.length) {
+ var error = new Error("insert raw message size does not match message header size [" + document.length + "] != [" + object_size + "]");
+ error.name = 'MongoError';
+ throw error;
+ }
+ }
+
+ this.documents.push(document);
+ return this;
+};
+
+/*
+struct {
+ MsgHeader header; // standard message header
+ int32 ZERO; // 0 - reserved for future use
+ cstring fullCollectionName; // "dbname.collectionname"
+ BSON[] documents; // one or more documents to insert into the collection
+}
+*/
+InsertCommand.prototype.toBinary = function() {
+ // Calculate total length of the document
+ var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + (4 * 4);
+ // var docLength = 0
+ for(var i = 0; i < this.documents.length; i++) {
+ if(Buffer.isBuffer(this.documents[i])) {
+ totalLengthOfCommand += this.documents[i].length;
+ } else {
+ // Calculate size of document
+ totalLengthOfCommand += this.db.bson.calculateObjectSize(this.documents[i], this.serializeFunctions, true);
+ }
+ }
+
+ // Let's build the single pass buffer command
+ var _index = 0;
+ var _command = new Buffer(totalLengthOfCommand);
+ // Write the header information to the buffer
+ _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
+ _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
+ _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
+ _command[_index] = totalLengthOfCommand & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write the request ID
+ _command[_index + 3] = (this.requestId >> 24) & 0xff;
+ _command[_index + 2] = (this.requestId >> 16) & 0xff;
+ _command[_index + 1] = (this.requestId >> 8) & 0xff;
+ _command[_index] = this.requestId & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write zero
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ // Write the op_code for the command
+ _command[_index + 3] = (InsertCommand.OP_INSERT >> 24) & 0xff;
+ _command[_index + 2] = (InsertCommand.OP_INSERT >> 16) & 0xff;
+ _command[_index + 1] = (InsertCommand.OP_INSERT >> 8) & 0xff;
+ _command[_index] = InsertCommand.OP_INSERT & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write flags if any
+ _command[_index + 3] = (this.flags >> 24) & 0xff;
+ _command[_index + 2] = (this.flags >> 16) & 0xff;
+ _command[_index + 1] = (this.flags >> 8) & 0xff;
+ _command[_index] = this.flags & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write the collection name to the command
+ _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
+ _command[_index - 1] = 0;
+
+ // Write all the bson documents to the buffer at the index offset
+ for(var i = 0; i < this.documents.length; i++) {
+ // Document binary length
+ var documentLength = 0
+ var object = this.documents[i];
+
+ // Serialize the selector
+ // If we are passing a raw buffer, do minimal validation
+ if(Buffer.isBuffer(object)) {
+ documentLength = object.length;
+ // Copy the data into the current buffer
+ object.copy(_command, _index);
+ } else {
+ // Serialize the document straight to the buffer
+ documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
+ }
+
+ // Write the length to the document
+ _command[_index + 3] = (documentLength >> 24) & 0xff;
+ _command[_index + 2] = (documentLength >> 16) & 0xff;
+ _command[_index + 1] = (documentLength >> 8) & 0xff;
+ _command[_index] = documentLength & 0xff;
+ // Update index in buffer
+ _index = _index + documentLength;
+ // Add terminating 0 for the object
+ _command[_index - 1] = 0;
+ }
+
+ return _command;
+};
diff --git a/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js b/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js
new file mode 100644
index 0000000..d8ccb0c
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js
@@ -0,0 +1,98 @@
+var BaseCommand = require('./base_command').BaseCommand,
+ inherits = require('util').inherits,
+ binaryutils = require('../utils');
+
+/**
+ Insert Document Command
+**/
+var KillCursorCommand = exports.KillCursorCommand = function(db, cursorIds) {
+ BaseCommand.call(this);
+
+ this.cursorIds = cursorIds;
+ this.db = db;
+};
+
+inherits(KillCursorCommand, BaseCommand);
+
+KillCursorCommand.OP_KILL_CURSORS = 2007;
+
+/*
+struct {
+ MsgHeader header; // standard message header
+ int32 ZERO; // 0 - reserved for future use
+ int32 numberOfCursorIDs; // number of cursorIDs in message
+ int64[] cursorIDs; // array of cursorIDs to close
+}
+*/
+KillCursorCommand.prototype.toBinary = function() {
+ // Calculate total length of the document
+ var totalLengthOfCommand = 4 + 4 + (4 * 4) + (this.cursorIds.length * 8);
+ // Let's build the single pass buffer command
+ var _index = 0;
+ var _command = new Buffer(totalLengthOfCommand);
+ // Write the header information to the buffer
+ _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
+ _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
+ _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
+ _command[_index] = totalLengthOfCommand & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write the request ID
+ _command[_index + 3] = (this.requestId >> 24) & 0xff;
+ _command[_index + 2] = (this.requestId >> 16) & 0xff;
+ _command[_index + 1] = (this.requestId >> 8) & 0xff;
+ _command[_index] = this.requestId & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write zero
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ // Write the op_code for the command
+ _command[_index + 3] = (KillCursorCommand.OP_KILL_CURSORS >> 24) & 0xff;
+ _command[_index + 2] = (KillCursorCommand.OP_KILL_CURSORS >> 16) & 0xff;
+ _command[_index + 1] = (KillCursorCommand.OP_KILL_CURSORS >> 8) & 0xff;
+ _command[_index] = KillCursorCommand.OP_KILL_CURSORS & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ // Write zero
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+
+ // Number of cursors to kill
+ var numberOfCursors = this.cursorIds.length;
+ _command[_index + 3] = (numberOfCursors >> 24) & 0xff;
+ _command[_index + 2] = (numberOfCursors >> 16) & 0xff;
+ _command[_index + 1] = (numberOfCursors >> 8) & 0xff;
+ _command[_index] = numberOfCursors & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ // Encode all the cursors
+ for(var i = 0; i < this.cursorIds.length; i++) {
+ // Encode the cursor id
+ var low_bits = this.cursorIds[i].getLowBits();
+ // Encode low bits
+ _command[_index + 3] = (low_bits >> 24) & 0xff;
+ _command[_index + 2] = (low_bits >> 16) & 0xff;
+ _command[_index + 1] = (low_bits >> 8) & 0xff;
+ _command[_index] = low_bits & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ var high_bits = this.cursorIds[i].getHighBits();
+ // Encode high bits
+ _command[_index + 3] = (high_bits >> 24) & 0xff;
+ _command[_index + 2] = (high_bits >> 16) & 0xff;
+ _command[_index + 1] = (high_bits >> 8) & 0xff;
+ _command[_index] = high_bits & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ }
+
+ return _command;
+};
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/commands/query_command.js b/node_modules/mongodb/lib/mongodb/commands/query_command.js
new file mode 100644
index 0000000..76829d9
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/commands/query_command.js
@@ -0,0 +1,261 @@
+var BaseCommand = require('./base_command').BaseCommand,
+ inherits = require('util').inherits;
+
+/**
+ Insert Document Command
+**/
+var QueryCommand = exports.QueryCommand = function(db, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector, options) {
+ BaseCommand.call(this);
+
+ // Validate correctness off the selector
+ var object = query,
+ object_size;
+ if(Buffer.isBuffer(object)) {
+ object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
+ if(object_size != object.length) {
+ var error = new Error("query selector raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
+ error.name = 'MongoError';
+ throw error;
+ }
+ }
+
+ object = returnFieldSelector;
+ if(Buffer.isBuffer(object)) {
+ object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
+ if(object_size != object.length) {
+ var error = new Error("query fields raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
+ error.name = 'MongoError';
+ throw error;
+ }
+ }
+
+ // Make sure we don't get a null exception
+ options = options == null ? {} : options;
+ // Set up options
+ this.collectionName = collectionName;
+ this.queryOptions = queryOptions;
+ this.numberToSkip = numberToSkip;
+ this.numberToReturn = numberToReturn;
+
+ // Ensure we have no null query
+ query = query == null ? {} : query;
+ // Wrap query in the $query parameter so we can add read preferences for mongos
+ this.query = query;
+ this.returnFieldSelector = returnFieldSelector;
+ this.db = db;
+
+ // Let us defined on a command basis if we want functions to be serialized or not
+ if(options['serializeFunctions'] != null && options['serializeFunctions']) {
+ this.serializeFunctions = true;
+ }
+};
+
+inherits(QueryCommand, BaseCommand);
+
+QueryCommand.OP_QUERY = 2004;
+
+/*
+ * Adds the read prefrence to the current command
+ */
+QueryCommand.prototype.setMongosReadPreference = function(readPreference, tags) {
+ // If we have readPreference set to true set to secondary prefered
+ if(readPreference == true) {
+ readPreference = 'secondaryPreferred';
+ } else if(readPreference == 'false') {
+ readPreference = 'primary';
+ }
+
+ // Force the slave ok flag to be set if we are not using primary read preference
+ if(readPreference != false && readPreference != 'primary') {
+ this.queryOptions |= QueryCommand.OPTS_SLAVE;
+ }
+
+ // Backward compatibility, ensure $query only set on read preference so 1.8.X works
+ if((readPreference != null || tags != null) && this.query['$query'] == null) {
+ this.query = {'$query': this.query};
+ }
+
+ // If we have no readPreference set and no tags, check if the slaveOk bit is set
+ if(readPreference == null && tags == null) {
+ // If we have a slaveOk bit set the read preference for MongoS
+ if(this.queryOptions & QueryCommand.OPTS_SLAVE) {
+ this.query['$readPreference'] = {mode: 'secondary'}
+ } else {
+ this.query['$readPreference'] = {mode: 'primary'}
+ }
+ }
+
+ // Build read preference object
+ if(typeof readPreference == 'object' && readPreference['_type'] == 'ReadPreference') {
+ this.query['$readPreference'] = readPreference.toObject();
+ } else if(readPreference != null) {
+ // Add the read preference
+ this.query['$readPreference'] = {mode: readPreference};
+
+ // If we have tags let's add them
+ if(tags != null) {
+ this.query['$readPreference']['tags'] = tags;
+ }
+ }
+}
+
+/*
+struct {
+ MsgHeader header; // standard message header
+ int32 opts; // query options. See below for details.
+ cstring fullCollectionName; // "dbname.collectionname"
+ int32 numberToSkip; // number of documents to skip when returning results
+ int32 numberToReturn; // number of documents to return in the first OP_REPLY
+ BSON query ; // query object. See below for details.
+ [ BSON returnFieldSelector; ] // OPTIONAL : selector indicating the fields to return. See below for details.
+}
+*/
+QueryCommand.prototype.toBinary = function() {
+ // Total length of the command
+ var totalLengthOfCommand = 0;
+ // Calculate total length of the document
+ if(Buffer.isBuffer(this.query)) {
+ totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.query.length + (4 * 4);
+ } else {
+ totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.db.bson.calculateObjectSize(this.query, this.serializeFunctions, true) + (4 * 4);
+ }
+
+ // Calculate extra fields size
+ if(this.returnFieldSelector != null && !(Buffer.isBuffer(this.returnFieldSelector))) {
+ if(Object.keys(this.returnFieldSelector).length > 0) {
+ totalLengthOfCommand += this.db.bson.calculateObjectSize(this.returnFieldSelector, this.serializeFunctions, true);
+ }
+ } else if(Buffer.isBuffer(this.returnFieldSelector)) {
+ totalLengthOfCommand += this.returnFieldSelector.length;
+ }
+
+ // Let's build the single pass buffer command
+ var _index = 0;
+ var _command = new Buffer(totalLengthOfCommand);
+ // Write the header information to the buffer
+ _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
+ _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
+ _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
+ _command[_index] = totalLengthOfCommand & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write the request ID
+ _command[_index + 3] = (this.requestId >> 24) & 0xff;
+ _command[_index + 2] = (this.requestId >> 16) & 0xff;
+ _command[_index + 1] = (this.requestId >> 8) & 0xff;
+ _command[_index] = this.requestId & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write zero
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ // Write the op_code for the command
+ _command[_index + 3] = (QueryCommand.OP_QUERY >> 24) & 0xff;
+ _command[_index + 2] = (QueryCommand.OP_QUERY >> 16) & 0xff;
+ _command[_index + 1] = (QueryCommand.OP_QUERY >> 8) & 0xff;
+ _command[_index] = QueryCommand.OP_QUERY & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ // Write the query options
+ _command[_index + 3] = (this.queryOptions >> 24) & 0xff;
+ _command[_index + 2] = (this.queryOptions >> 16) & 0xff;
+ _command[_index + 1] = (this.queryOptions >> 8) & 0xff;
+ _command[_index] = this.queryOptions & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ // Write the collection name to the command
+ _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
+ _command[_index - 1] = 0;
+
+ // Write the number of documents to skip
+ _command[_index + 3] = (this.numberToSkip >> 24) & 0xff;
+ _command[_index + 2] = (this.numberToSkip >> 16) & 0xff;
+ _command[_index + 1] = (this.numberToSkip >> 8) & 0xff;
+ _command[_index] = this.numberToSkip & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ // Write the number of documents to return
+ _command[_index + 3] = (this.numberToReturn >> 24) & 0xff;
+ _command[_index + 2] = (this.numberToReturn >> 16) & 0xff;
+ _command[_index + 1] = (this.numberToReturn >> 8) & 0xff;
+ _command[_index] = this.numberToReturn & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ // Document binary length
+ var documentLength = 0
+ var object = this.query;
+
+ // Serialize the selector
+ if(Buffer.isBuffer(object)) {
+ documentLength = object.length;
+ // Copy the data into the current buffer
+ object.copy(_command, _index);
+ } else {
+ // Serialize the document straight to the buffer
+ documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
+ }
+
+ // Write the length to the document
+ _command[_index + 3] = (documentLength >> 24) & 0xff;
+ _command[_index + 2] = (documentLength >> 16) & 0xff;
+ _command[_index + 1] = (documentLength >> 8) & 0xff;
+ _command[_index] = documentLength & 0xff;
+ // Update index in buffer
+ _index = _index + documentLength;
+ // Add terminating 0 for the object
+ _command[_index - 1] = 0;
+
+ // Push field selector if available
+ if(this.returnFieldSelector != null && !(Buffer.isBuffer(this.returnFieldSelector))) {
+ if(Object.keys(this.returnFieldSelector).length > 0) {
+ var documentLength = this.db.bson.serializeWithBufferAndIndex(this.returnFieldSelector, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
+ // Write the length to the document
+ _command[_index + 3] = (documentLength >> 24) & 0xff;
+ _command[_index + 2] = (documentLength >> 16) & 0xff;
+ _command[_index + 1] = (documentLength >> 8) & 0xff;
+ _command[_index] = documentLength & 0xff;
+ // Update index in buffer
+ _index = _index + documentLength;
+ // Add terminating 0 for the object
+ _command[_index - 1] = 0;
+ }
+ } if(this.returnFieldSelector != null && Buffer.isBuffer(this.returnFieldSelector)) {
+ // Document binary length
+ var documentLength = 0
+ var object = this.returnFieldSelector;
+
+ // Serialize the selector
+ documentLength = object.length;
+ // Copy the data into the current buffer
+ object.copy(_command, _index);
+
+ // Write the length to the document
+ _command[_index + 3] = (documentLength >> 24) & 0xff;
+ _command[_index + 2] = (documentLength >> 16) & 0xff;
+ _command[_index + 1] = (documentLength >> 8) & 0xff;
+ _command[_index] = documentLength & 0xff;
+ // Update index in buffer
+ _index = _index + documentLength;
+ // Add terminating 0 for the object
+ _command[_index - 1] = 0;
+ }
+
+ // Return finished command
+ return _command;
+};
+
+// Constants
+QueryCommand.OPTS_NONE = 0;
+QueryCommand.OPTS_TAILABLE_CURSOR = 2;
+QueryCommand.OPTS_SLAVE = 4;
+QueryCommand.OPTS_OPLOG_REPLY = 8;
+QueryCommand.OPTS_NO_CURSOR_TIMEOUT = 16;
+QueryCommand.OPTS_AWAIT_DATA = 32;
+QueryCommand.OPTS_EXHAUST = 64;
+QueryCommand.OPTS_PARTIAL = 128;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/commands/update_command.js b/node_modules/mongodb/lib/mongodb/commands/update_command.js
new file mode 100644
index 0000000..9829dea
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/commands/update_command.js
@@ -0,0 +1,174 @@
+var BaseCommand = require('./base_command').BaseCommand,
+ inherits = require('util').inherits;
+
+/**
+ Update Document Command
+**/
+var UpdateCommand = exports.UpdateCommand = function(db, collectionName, spec, document, options) {
+ BaseCommand.call(this);
+
+ var object = spec;
+ if(Buffer.isBuffer(object)) {
+ var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
+ if(object_size != object.length) {
+ var error = new Error("update spec raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
+ error.name = 'MongoError';
+ throw error;
+ }
+ }
+
+ var object = document;
+ if(Buffer.isBuffer(object)) {
+ var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
+ if(object_size != object.length) {
+ var error = new Error("update document raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
+ error.name = 'MongoError';
+ throw error;
+ }
+ }
+
+ this.collectionName = collectionName;
+ this.spec = spec;
+ this.document = document;
+ this.db = db;
+ this.serializeFunctions = false;
+
+ // Generate correct flags
+ var db_upsert = 0;
+ var db_multi_update = 0;
+ db_upsert = options != null && options['upsert'] != null ? (options['upsert'] == true ? 1 : 0) : db_upsert;
+ db_multi_update = options != null && options['multi'] != null ? (options['multi'] == true ? 1 : 0) : db_multi_update;
+
+ // Flags
+ this.flags = parseInt(db_multi_update.toString() + db_upsert.toString(), 2);
+ // Let us defined on a command basis if we want functions to be serialized or not
+ if(options['serializeFunctions'] != null && options['serializeFunctions']) {
+ this.serializeFunctions = true;
+ }
+};
+
+inherits(UpdateCommand, BaseCommand);
+
+UpdateCommand.OP_UPDATE = 2001;
+
+/*
+struct {
+ MsgHeader header; // standard message header
+ int32 ZERO; // 0 - reserved for future use
+ cstring fullCollectionName; // "dbname.collectionname"
+ int32 flags; // bit vector. see below
+ BSON spec; // the query to select the document
+ BSON document; // the document data to update with or insert
+}
+*/
+UpdateCommand.prototype.toBinary = function() {
+ // Calculate total length of the document
+ var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson.calculateObjectSize(this.spec, false, true) +
+ this.db.bson.calculateObjectSize(this.document, this.serializeFunctions, true) + (4 * 4);
+
+ // Let's build the single pass buffer command
+ var _index = 0;
+ var _command = new Buffer(totalLengthOfCommand);
+ // Write the header information to the buffer
+ _command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
+ _command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
+ _command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
+ _command[_index] = totalLengthOfCommand & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write the request ID
+ _command[_index + 3] = (this.requestId >> 24) & 0xff;
+ _command[_index + 2] = (this.requestId >> 16) & 0xff;
+ _command[_index + 1] = (this.requestId >> 8) & 0xff;
+ _command[_index] = this.requestId & 0xff;
+ // Adjust index
+ _index = _index + 4;
+ // Write zero
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ // Write the op_code for the command
+ _command[_index + 3] = (UpdateCommand.OP_UPDATE >> 24) & 0xff;
+ _command[_index + 2] = (UpdateCommand.OP_UPDATE >> 16) & 0xff;
+ _command[_index + 1] = (UpdateCommand.OP_UPDATE >> 8) & 0xff;
+ _command[_index] = UpdateCommand.OP_UPDATE & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ // Write zero
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+ _command[_index++] = 0;
+
+ // Write the collection name to the command
+ _index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
+ _command[_index - 1] = 0;
+
+ // Write the update flags
+ _command[_index + 3] = (this.flags >> 24) & 0xff;
+ _command[_index + 2] = (this.flags >> 16) & 0xff;
+ _command[_index + 1] = (this.flags >> 8) & 0xff;
+ _command[_index] = this.flags & 0xff;
+ // Adjust index
+ _index = _index + 4;
+
+ // Document binary length
+ var documentLength = 0
+ var object = this.spec;
+
+ // Serialize the selector
+ // If we are passing a raw buffer, do minimal validation
+ if(Buffer.isBuffer(object)) {
+ var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
+ if(object_size != object.length) throw new Error("raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
+ documentLength = object.length;
+ // Copy the data into the current buffer
+ object.copy(_command, _index);
+ } else {
+ documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, false) - _index + 1;
+ }
+
+ // Write the length to the document
+ _command[_index + 3] = (documentLength >> 24) & 0xff;
+ _command[_index + 2] = (documentLength >> 16) & 0xff;
+ _command[_index + 1] = (documentLength >> 8) & 0xff;
+ _command[_index] = documentLength & 0xff;
+ // Update index in buffer
+ _index = _index + documentLength;
+ // Add terminating 0 for the object
+ _command[_index - 1] = 0;
+
+ // Document binary length
+ var documentLength = 0
+ var object = this.document;
+
+ // Serialize the document
+ // If we are passing a raw buffer, do minimal validation
+ if(Buffer.isBuffer(object)) {
+ var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
+ if(object_size != object.length) throw new Error("raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
+ documentLength = object.length;
+ // Copy the data into the current buffer
+ object.copy(_command, _index);
+ } else {
+ documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
+ }
+
+ // Write the length to the document
+ _command[_index + 3] = (documentLength >> 24) & 0xff;
+ _command[_index + 2] = (documentLength >> 16) & 0xff;
+ _command[_index + 1] = (documentLength >> 8) & 0xff;
+ _command[_index] = documentLength & 0xff;
+ // Update index in buffer
+ _index = _index + documentLength;
+ // Add terminating 0 for the object
+ _command[_index - 1] = 0;
+
+ return _command;
+};
+
+// Constants
+UpdateCommand.DB_UPSERT = 0;
+UpdateCommand.DB_MULTI_UPDATE = 1;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/connection/base.js b/node_modules/mongodb/lib/mongodb/connection/base.js
new file mode 100644
index 0000000..93b236e
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/base.js
@@ -0,0 +1,465 @@
+var EventEmitter = require('events').EventEmitter
+ , inherits = require('util').inherits
+ , mongodb_cr_authenticate = require('../auth/mongodb_cr.js').authenticate
+ , mongodb_gssapi_authenticate = require('../auth/mongodb_gssapi.js').authenticate
+ , mongodb_sspi_authenticate = require('../auth/mongodb_sspi.js').authenticate;
+
+var id = 0;
+
+/**
+ * Internal class for callback storage
+ * @ignore
+ */
+var CallbackStore = function() {
+ // Make class an event emitter
+ EventEmitter.call(this);
+ // Add a info about call variable
+ this._notReplied = {};
+ this.id = id++;
+}
+
+/**
+ * @ignore
+ */
+inherits(CallbackStore, EventEmitter);
+
+CallbackStore.prototype.notRepliedToIds = function() {
+ return Object.keys(this._notReplied);
+}
+
+CallbackStore.prototype.callbackInfo = function(id) {
+ return this._notReplied[id];
+}
+
+/**
+ * Internal class for holding non-executed commands
+ * @ignore
+ */
+var NonExecutedOperationStore = function(config) {
+ this.config = config;
+ this.commands = {
+ read: []
+ , write_reads: []
+ , write: []
+ };
+}
+
+NonExecutedOperationStore.prototype.write = function(op) {
+ this.commands.write.push(op);
+}
+
+NonExecutedOperationStore.prototype.read_from_writer = function(op) {
+ this.commands.write_reads.push(op);
+}
+
+NonExecutedOperationStore.prototype.read = function(op) {
+ this.commands.read.push(op);
+}
+
+NonExecutedOperationStore.prototype.execute_queries = function(executeInsertCommand) {
+ var connection = this.config.checkoutReader();
+ if(connection == null || connection instanceof Error) return;
+
+ // Write out all the queries
+ while(this.commands.read.length > 0) {
+ // Get the next command
+ var command = this.commands.read.shift();
+ // command['options'].connection = this.config.checkoutReader();
+ command.options.connection = connection;
+ // Execute the next command
+ command.executeQueryCommand(command.db, command.db_command, command.options, command.callback);
+ }
+}
+
+NonExecutedOperationStore.prototype.execute_writes = function() {
+ var connection = this.config.checkoutWriter();
+ if(connection == null || connection instanceof Error) return;
+
+ // Write out all the queries to the primary
+ while(this.commands.write_reads.length > 0) {
+ // Get the next command
+ var command = this.commands.write_reads.shift();
+ command.options.connection = connection;
+ // Execute the next command
+ command.executeQueryCommand(command.db, command.db_command, command.options, command.callback);
+ }
+
+ // Execute all write operations
+ while(this.commands.write.length > 0) {
+ // Get the next command
+ var command = this.commands.write.shift();
+ // Set the connection
+ command.options.connection = connection;
+ // Execute the next command
+ command.executeInsertCommand(command.db, command.db_command, command.options, command.callback);
+ }
+}
+
+/**
+ * Internal class for authentication storage
+ * @ignore
+ */
+var AuthStore = function() {
+ this._auths = [];
+}
+
+AuthStore.prototype.add = function(authMechanism, dbName, username, password, authdbName) {
+ // Check for duplicates
+ if(!this.contains(dbName)) {
+ // Base config
+ var config = {
+ 'username':username
+ , 'password':password
+ , 'db': dbName
+ , 'authMechanism': authMechanism
+ };
+
+ // Add auth source if passed in
+ if(typeof authdbName == 'string') {
+ config['authdb'] = authdbName;
+ }
+
+ // Push the config
+ this._auths.push(config);
+ }
+}
+
+AuthStore.prototype.contains = function(dbName) {
+ for(var i = 0; i < this._auths.length; i++) {
+ if(this._auths[i].db == dbName) return true;
+ }
+
+ return false;
+}
+
+AuthStore.prototype.remove = function(dbName) {
+ var newAuths = [];
+
+ // Filter out all the login details
+ for(var i = 0; i < this._auths.length; i++) {
+ if(this._auths[i].db != dbName) newAuths.push(this._auths[i]);
+ }
+
+ // Set the filtered list
+ this._auths = newAuths;
+}
+
+AuthStore.prototype.get = function(index) {
+ return this._auths[index];
+}
+
+AuthStore.prototype.length = function() {
+ return this._auths.length;
+}
+
+AuthStore.prototype.toArray = function() {
+ return this._auths.slice(0);
+}
+
+/**
+ * Internal class for storing db references
+ * @ignore
+ */
+var DbStore = function() {
+ this._dbs = [];
+}
+
+DbStore.prototype.add = function(db) {
+ // this._dbs.push(db);
+ var found = false;
+ // Only add if it does not exist already
+ for(var i = 0; i < this._dbs.length; i++) {
+ if(db.databaseName == this._dbs[i].databaseName) found = true;
+ }
+
+ if(!found) this._dbs.push(db);
+}
+
+DbStore.prototype.reset = function() {
+ this._dbs = [];
+}
+
+DbStore.prototype.emit = function(event, message, object, reset, filterDb) {
+ if(reset) {
+ while(this._dbs.length > 0) {
+ var db = this._dbs.shift();
+ // Only emit if there is a listener
+ if(db.listeners(event).length > 0) {
+ if(filterDb == null || filterDb.databaseName !== db.databaseName
+ || filterDb.tag !== db.tag) {
+ db.emit(event, message, object);
+ }
+ }
+ }
+ } else {
+ for(var i = 0; i < this._dbs.length; i++) {
+ if(this._dbs[i].listeners(event).length > 0) {
+ if(filterDb == null || filterDb.databaseName !== this._dbs[i].databaseName
+ || filterDb.tag !== this._dbs[i].tag) {
+ this._dbs[i].emit(event, message, object);
+ }
+ }
+ }
+ }
+}
+
+var Base = function Base() {
+ EventEmitter.call(this);
+
+ // Callback store is part of connection specification
+ if(Base._callBackStore == null) {
+ Base._callBackStore = new CallbackStore();
+ }
+
+ // Create a new callback store
+ this._callBackStore = new CallbackStore();
+ // All commands not being executed
+ this._commandsStore = new NonExecutedOperationStore(this);
+ // Create a new auth store
+ this.auth = new AuthStore();
+ // Contains all the dbs attached to this server config
+ this._dbStore = new DbStore();
+}
+
+/**
+ * @ignore
+ */
+inherits(Base, EventEmitter);
+
+/**
+ * @ignore
+ */
+Base.prototype._apply_auths = function(db, callback) {
+ _apply_auths_serially(this, db, this.auth.toArray(), callback);
+}
+
+var _apply_auths_serially = function(self, db, auths, callback) {
+ if(auths.length == 0) return callback(null, null);
+ // Get the first auth
+ var auth = auths.shift();
+ var connections = self.allRawConnections();
+ var connectionsLeft = connections.length;
+
+ // Let's apply it to all raw connections
+ for(var i = 0; i < connections.length; i++) {
+ var options = {connection: connections[i]};
+
+ if(auth.authMechanism == 'GSSAPI') {
+ var connectionHandler = function(err, result) {
+ connectionsLeft = connectionsLeft - 1;
+ // If no more connections are left return
+ if(connectionsLeft == 0) {
+ return _apply_auths_serially(self, db, auths, callback);
+ }
+ }
+
+ // We have the kerberos library, execute auth process
+ if(process.platform == 'win32') {
+ mongodb_sspi_authenticate(db, auth.username, auth.password, auth.authdb, options, callback);
+ } else {
+ mongodb_gssapi_authenticate(db, auth.username, auth.password, auth.authdb, options, callback);
+ }
+ } else if(auth.authMechanism == 'MONGODB-CR') {
+ mongodb_cr_authenticate(db, auth.username, auth.password, auth.authdb, options, callback);
+ }
+ }
+}
+
+/**
+ * Fire all the errors
+ * @ignore
+ */
+Base.prototype.__executeAllCallbacksWithError = function(err) {
+ // Check all callbacks
+ var keys = Object.keys(this._callBackStore._notReplied);
+ // For each key check if it's a callback that needs to be returned
+ for(var j = 0; j < keys.length; j++) {
+ var info = this._callBackStore._notReplied[keys[j]];
+ // Check if we have a chained command (findAndModify)
+ if(info && info['chained'] && Array.isArray(info['chained']) && info['chained'].length > 0) {
+ var chained = info['chained'];
+ // Only callback once and the last one is the right one
+ var finalCallback = chained.pop();
+ // Emit only the last event
+ this._callBackStore.emit(finalCallback, err, null);
+
+ // Put back the final callback to ensure we don't call all commands in the chain
+ chained.push(finalCallback);
+
+ // Remove all chained callbacks
+ for(var i = 0; i < chained.length; i++) {
+ delete this._callBackStore._notReplied[chained[i]];
+ }
+ // Remove the key
+ delete this._callBackStore._notReplied[keys[j]];
+ } else {
+ this._callBackStore.emit(keys[j], err, null);
+ // Remove the key
+ delete this._callBackStore._notReplied[keys[j]];
+ }
+ }
+}
+
+/**
+ * Fire all the errors
+ * @ignore
+ */
+Base.prototype.__executeAllServerSpecificErrorCallbacks = function(host, port, err) {
+ // Check all callbacks
+ var keys = Object.keys(this._callBackStore._notReplied);
+ // For each key check if it's a callback that needs to be returned
+ for(var j = 0; j < keys.length; j++) {
+ var info = this._callBackStore._notReplied[keys[j]];
+
+ if(info.connection) {
+ // Unpack the connection settings
+ var _host = info.connection.socketOptions.host;
+ var _port = info.connection.socketOptions.port;
+ // Check if we have a chained command (findAndModify)
+ if(info && info['chained']
+ && Array.isArray(info['chained'])
+ && info['chained'].length > 0
+ && _port == port && _host == host) {
+ var chained = info['chained'];
+ // Only callback once and the last one is the right one
+ var finalCallback = chained.pop();
+ // Emit only the last event
+ this._callBackStore.emit(finalCallback, err, null);
+
+ // Put back the final callback to ensure we don't call all commands in the chain
+ chained.push(finalCallback);
+
+ // Remove all chained callbacks
+ for(var i = 0; i < chained.length; i++) {
+ delete this._callBackStore._notReplied[chained[i]];
+ }
+ // Remove the key
+ delete this._callBackStore._notReplied[keys[j]];
+ } else if(_port == port && _host == host) {
+ this._callBackStore.emit(keys[j], err, null);
+ // Remove the key
+ delete this._callBackStore._notReplied[keys[j]];
+ }
+ }
+ }
+}
+
+/**
+ * Register a handler
+ * @ignore
+ * @api private
+ */
+Base.prototype._registerHandler = function(db_command, raw, connection, exhaust, callback) {
+ // If we have an array of commands, chain them
+ var chained = Array.isArray(db_command);
+
+ // Check if we have exhausted
+ if(typeof exhaust == 'function') {
+ callback = exhaust;
+ exhaust = false;
+ }
+
+ // If they are chained we need to add a special handler situation
+ if(chained) {
+ // List off chained id's
+ var chainedIds = [];
+ // Add all id's
+ for(var i = 0; i < db_command.length; i++) chainedIds.push(db_command[i].getRequestId().toString());
+ // Register all the commands together
+ for(var i = 0; i < db_command.length; i++) {
+ var command = db_command[i];
+ // Add the callback to the store
+ this._callBackStore.once(command.getRequestId(), callback);
+ // Add the information about the reply
+ this._callBackStore._notReplied[command.getRequestId().toString()] = {start: new Date().getTime(), 'raw': raw, chained:chainedIds, connection:connection, exhaust:false};
+ }
+ } else {
+ // Add the callback to the list of handlers
+ this._callBackStore.once(db_command.getRequestId(), callback);
+ // Add the information about the reply
+ this._callBackStore._notReplied[db_command.getRequestId().toString()] = {start: new Date().getTime(), 'raw': raw, connection:connection, exhaust:exhaust};
+ }
+}
+
+/**
+ * Re-Register a handler, on the cursor id f.ex
+ * @ignore
+ * @api private
+ */
+Base.prototype._reRegisterHandler = function(newId, object, callback) {
+ // Add the callback to the list of handlers
+ this._callBackStore.once(newId, object.callback.listener);
+ // Add the information about the reply
+ this._callBackStore._notReplied[newId] = object.info;
+}
+
+/**
+ *
+ * @ignore
+ * @api private
+ */
+Base.prototype._callHandler = function(id, document, err) {
+ // If there is a callback peform it
+ if(this._callBackStore.listeners(id).length >= 1) {
+ // Get info object
+ var info = this._callBackStore._notReplied[id];
+ // Delete the current object
+ delete this._callBackStore._notReplied[id];
+ // Emit to the callback of the object
+ this._callBackStore.emit(id, err, document, info.connection);
+ }
+}
+
+/**
+ *
+ * @ignore
+ * @api private
+ */
+Base.prototype._hasHandler = function(id) {
+ // If there is a callback peform it
+ return this._callBackStore.listeners(id).length >= 1;
+}
+
+/**
+ *
+ * @ignore
+ * @api private
+ */
+Base.prototype._removeHandler = function(id) {
+ // Remove the information
+ if(this._callBackStore._notReplied[id] != null) delete this._callBackStore._notReplied[id];
+ // Remove the callback if it's registered
+ this._callBackStore.removeAllListeners(id);
+ // Force cleanup _events, node.js seems to set it as a null value
+ if(this._callBackStore._events != null) delete this._callBackStore._events[id];
+}
+
+/**
+ *
+ * @ignore
+ * @api private
+ */
+Base.prototype._findHandler = function(id) {
+ var info = this._callBackStore._notReplied[id];
+ // Return the callback
+ return {info:info, callback:(this._callBackStore.listeners(id).length >= 1) ? this._callBackStore.listeners(id)[0] : null}
+}
+
+/**
+ *
+ * @ignore
+ * @api private
+ */
+Base.prototype._emitAcrossAllDbInstances = function(server, filterDb, event, message, object, resetConnection) {
+ if(resetConnection) {
+ for(var i = 0; i < this._dbStore._dbs.length; i++) {
+ if(typeof this._dbStore._dbs[i].openCalled != 'undefined')
+ this._dbStore._dbs[i].openCalled = false;
+ }
+ }
+
+ // Fire event
+ this._dbStore.emit(event, message, object, resetConnection, filterDb);
+}
+
+exports.Base = Base;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/connection/connection.js b/node_modules/mongodb/lib/mongodb/connection/connection.js
new file mode 100644
index 0000000..6753fd2
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/connection.js
@@ -0,0 +1,505 @@
+var utils = require('./connection_utils'),
+ inherits = require('util').inherits,
+ net = require('net'),
+ EventEmitter = require('events').EventEmitter,
+ inherits = require('util').inherits,
+ binaryutils = require('../utils'),
+ tls = require('tls');
+
+var Connection = exports.Connection = function(id, socketOptions) {
+ // Set up event emitter
+ EventEmitter.call(this);
+ // Store all socket options
+ this.socketOptions = socketOptions ? socketOptions : {host:'localhost', port:27017, domainSocket:false};
+ // Set keep alive default if not overriden
+ if(this.socketOptions.keepAlive == null && (process.platform !== "sunos" || process.platform !== "win32")) this.socketOptions.keepAlive = 100;
+ // Id for the connection
+ this.id = id;
+ // State of the connection
+ this.connected = false;
+ // Set if this is a domain socket
+ this.domainSocket = this.socketOptions.domainSocket;
+
+ //
+ // Connection parsing state
+ //
+ this.maxBsonSize = socketOptions.maxBsonSize ? socketOptions.maxBsonSize : Connection.DEFAULT_MAX_BSON_SIZE;
+ this.maxMessageSizeBytes = socketOptions.maxMessageSizeBytes ? socketOptions.maxMessageSizeBytes : Connection.DEFAULT_MAX_MESSAGE_SIZE;
+ // Contains the current message bytes
+ this.buffer = null;
+ // Contains the current message size
+ this.sizeOfMessage = 0;
+ // Contains the readIndex for the messaage
+ this.bytesRead = 0;
+ // Contains spill over bytes from additional messages
+ this.stubBuffer = 0;
+
+ // Just keeps list of events we allow
+ this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[], timeout:[], end:[]};
+
+ // Just keeps list of events we allow
+ resetHandlers(this, false);
+}
+
+// Set max bson size
+Connection.DEFAULT_MAX_BSON_SIZE = 1024 * 1024 * 4;
+// Set default to max bson to avoid overflow or bad guesses
+Connection.DEFAULT_MAX_MESSAGE_SIZE = Connection.DEFAULT_MAX_BSON_SIZE;
+
+// Inherit event emitter so we can emit stuff wohoo
+inherits(Connection, EventEmitter);
+
+Connection.prototype.start = function() {
+ var self = this;
+
+ // If we have a normal connection
+ if(this.socketOptions.ssl) {
+ // Create new connection instance
+ if(this.domainSocket) {
+ this.connection = net.createConnection(this.socketOptions.host);
+ } else {
+ this.connection = net.createConnection(this.socketOptions.port, this.socketOptions.host);
+ }
+ if(this.logger != null && this.logger.doDebug){
+ this.logger.debug("opened connection", this.socketOptions);
+ }
+ // Set options on the socket
+ this.connection.setTimeout(this.socketOptions.connectTimeoutMS != null ? this.socketOptions.connectTimeoutMS : this.socketOptions.timeout);
+ // Work around for 0.4.X
+ if(process.version.indexOf("v0.4") == -1) this.connection.setNoDelay(this.socketOptions.noDelay);
+ // Set keep alive if defined
+ if(process.version.indexOf("v0.4") == -1) {
+ if(this.socketOptions.keepAlive > 0) {
+ this.connection.setKeepAlive(true, this.socketOptions.keepAlive);
+ } else {
+ this.connection.setKeepAlive(false);
+ }
+ }
+
+ // Check if the driver should validate the certificate
+ var validate_certificates = this.socketOptions.sslValidate == true ? true : false;
+
+ // Create options for the tls connection
+ var tls_options = {
+ socket: this.connection
+ , rejectUnauthorized: false
+ }
+
+ // If we wish to validate the certificate we have provided a ca store
+ if(validate_certificates) {
+ tls_options.ca = this.socketOptions.sslCA;
+ }
+
+ // If we have a certificate to present
+ if(this.socketOptions.sslCert) {
+ tls_options.cert = this.socketOptions.sslCert;
+ tls_options.key = this.socketOptions.sslKey;
+ }
+
+ // If the driver has been provided a private key password
+ if(this.socketOptions.sslPass) {
+ tls_options.passphrase = this.socketOptions.sslPass;
+ }
+
+ // Contains the cleartext stream
+ var cleartext = null;
+ // Attempt to establish a TLS connection to the server
+ try {
+ cleartext = tls.connect(this.socketOptions.port, this.socketOptions.host, tls_options, function() {
+ // If we have a ssl certificate validation error return an error
+ if(cleartext.authorizationError && validate_certificates) {
+ // Emit an error
+ return self.emit("error", cleartext.authorizationError, self, {ssl:true});
+ }
+
+ // Connect to the server
+ connectHandler(self)();
+ })
+ } catch(err) {
+ return self.emit("error", "SSL connection failed", self, {ssl:true});
+ }
+
+ // Save the output stream
+ this.writeSteam = cleartext;
+
+ // Set up data handler for the clear stream
+ cleartext.on("data", createDataHandler(this));
+ // Do any handling of end event of the stream
+ cleartext.on("end", endHandler(this));
+ cleartext.on("error", errorHandler(this));
+
+ // Handle any errors
+ this.connection.on("error", errorHandler(this));
+ // Handle timeout
+ this.connection.on("timeout", timeoutHandler(this));
+ // Handle drain event
+ this.connection.on("drain", drainHandler(this));
+ // Handle the close event
+ this.connection.on("close", closeHandler(this));
+ } else {
+ // Create new connection instance
+ if(this.domainSocket) {
+ this.connection = net.createConnection(this.socketOptions.host);
+ } else {
+ this.connection = net.createConnection(this.socketOptions.port, this.socketOptions.host);
+ }
+ if(this.logger != null && this.logger.doDebug){
+ this.logger.debug("opened connection", this.socketOptions);
+ }
+
+ // Set options on the socket
+ this.connection.setTimeout(this.socketOptions.connectTimeoutMS != null ? this.socketOptions.connectTimeoutMS : this.socketOptions.timeout);
+ // Work around for 0.4.X
+ if(process.version.indexOf("v0.4") == -1) this.connection.setNoDelay(this.socketOptions.noDelay);
+ // Set keep alive if defined
+ if(process.version.indexOf("v0.4") == -1) {
+ if(this.socketOptions.keepAlive > 0) {
+ this.connection.setKeepAlive(true, this.socketOptions.keepAlive);
+ } else {
+ this.connection.setKeepAlive(false);
+ }
+ }
+
+ // Set up write stream
+ this.writeSteam = this.connection;
+ // Add handlers
+ this.connection.on("error", errorHandler(this));
+ // Add all handlers to the socket to manage it
+ this.connection.on("connect", connectHandler(this));
+ // this.connection.on("end", endHandler(this));
+ this.connection.on("data", createDataHandler(this));
+ this.connection.on("timeout", timeoutHandler(this));
+ this.connection.on("drain", drainHandler(this));
+ this.connection.on("close", closeHandler(this));
+ }
+}
+
+// Check if the sockets are live
+Connection.prototype.isConnected = function() {
+ return this.connected && !this.connection.destroyed && this.connection.writable && this.connection.readable;
+}
+
+// Write the data out to the socket
+Connection.prototype.write = function(command, callback) {
+ try {
+ // If we have a list off commands to be executed on the same socket
+ if(Array.isArray(command)) {
+ for(var i = 0; i < command.length; i++) {
+ var binaryCommand = command[i].toBinary()
+
+ if(!this.socketOptions['disableDriverBSONSizeCheck'] && binaryCommand.length > this.maxBsonSize)
+ return callback(new Error("Document exceeds maximum allowed bson size of " + this.maxBsonSize + " bytes"));
+
+ if(this.socketOptions['disableDriverBSONSizeCheck'] && binaryCommand.length > this.maxMessageSizeBytes) {
+ return callback(new Error("Command exceeds maximum message size of " + this.maxMessageSizeBytes + " bytes"));
+ }
+
+ if(this.logger != null && this.logger.doDebug)
+ this.logger.debug("writing command to mongodb", {binary: binaryCommand, json: command[i]});
+
+ var r = this.writeSteam.write(binaryCommand);
+ }
+ } else {
+ var binaryCommand = command.toBinary()
+
+ if(!this.socketOptions['disableDriverBSONSizeCheck'] && binaryCommand.length > this.maxBsonSize)
+ return callback(new Error("Document exceeds maximum allowed bson size of " + this.maxBsonSize + " bytes"));
+
+ if(this.socketOptions['disableDriverBSONSizeCheck'] && binaryCommand.length > this.maxMessageSizeBytes) {
+ return callback(new Error("Command exceeds maximum message size of " + this.maxMessageSizeBytes + " bytes"));
+ }
+
+ if(this.logger != null && this.logger.doDebug)
+ this.logger.debug("writing command to mongodb", {binary: binaryCommand, json: command});
+
+ var r = this.writeSteam.write(binaryCommand);
+ }
+ } catch (err) {
+ if(typeof callback === 'function') callback(err);
+ }
+}
+
+// Force the closure of the connection
+Connection.prototype.close = function() {
+ // clear out all the listeners
+ resetHandlers(this, true);
+ // Add a dummy error listener to catch any weird last moment errors (and ignore them)
+ this.connection.on("error", function() {})
+ // destroy connection
+ this.connection.destroy();
+ if(this.logger != null && this.logger.doDebug){
+ this.logger.debug("closed connection", this.connection);
+ }
+}
+
+// Reset all handlers
+var resetHandlers = function(self, clearListeners) {
+ self.eventHandlers = {error:[], connect:[], close:[], end:[], timeout:[], parseError:[], message:[]};
+
+ // If we want to clear all the listeners
+ if(clearListeners && self.connection != null) {
+ var keys = Object.keys(self.eventHandlers);
+ // Remove all listeners
+ for(var i = 0; i < keys.length; i++) {
+ self.connection.removeAllListeners(keys[i]);
+ }
+ }
+}
+
+//
+// Handlers
+//
+
+// Connect handler
+var connectHandler = function(self) {
+ return function(data) {
+ // Set connected
+ self.connected = true;
+ // Now that we are connected set the socket timeout
+ self.connection.setTimeout(self.socketOptions.socketTimeoutMS != null ? self.socketOptions.socketTimeoutMS : self.socketOptions.timeout);
+ // Emit the connect event with no error
+ self.emit("connect", null, self);
+ }
+}
+
+var createDataHandler = exports.Connection.createDataHandler = function(self) {
+ // We need to handle the parsing of the data
+ // and emit the messages when there is a complete one
+ return function(data) {
+ // Parse until we are done with the data
+ while(data.length > 0) {
+ // If we still have bytes to read on the current message
+ if(self.bytesRead > 0 && self.sizeOfMessage > 0) {
+ // Calculate the amount of remaining bytes
+ var remainingBytesToRead = self.sizeOfMessage - self.bytesRead;
+ // Check if the current chunk contains the rest of the message
+ if(remainingBytesToRead > data.length) {
+ // Copy the new data into the exiting buffer (should have been allocated when we know the message size)
+ data.copy(self.buffer, self.bytesRead);
+ // Adjust the number of bytes read so it point to the correct index in the buffer
+ self.bytesRead = self.bytesRead + data.length;
+
+ // Reset state of buffer
+ data = new Buffer(0);
+ } else {
+ // Copy the missing part of the data into our current buffer
+ data.copy(self.buffer, self.bytesRead, 0, remainingBytesToRead);
+ // Slice the overflow into a new buffer that we will then re-parse
+ data = data.slice(remainingBytesToRead);
+
+ // Emit current complete message
+ try {
+ var emitBuffer = self.buffer;
+ // Reset state of buffer
+ self.buffer = null;
+ self.sizeOfMessage = 0;
+ self.bytesRead = 0;
+ self.stubBuffer = null;
+ // Emit the buffer
+ self.emit("message", emitBuffer, self);
+ } catch(err) {
+ var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{
+ sizeOfMessage:self.sizeOfMessage,
+ bytesRead:self.bytesRead,
+ stubBuffer:self.stubBuffer}};
+ if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
+ // We got a parse Error fire it off then keep going
+ self.emit("parseError", errorObject, self);
+ }
+ }
+ } else {
+ // Stub buffer is kept in case we don't get enough bytes to determine the
+ // size of the message (< 4 bytes)
+ if(self.stubBuffer != null && self.stubBuffer.length > 0) {
+
+ // If we have enough bytes to determine the message size let's do it
+ if(self.stubBuffer.length + data.length > 4) {
+ // Prepad the data
+ var newData = new Buffer(self.stubBuffer.length + data.length);
+ self.stubBuffer.copy(newData, 0);
+ data.copy(newData, self.stubBuffer.length);
+ // Reassign for parsing
+ data = newData;
+
+ // Reset state of buffer
+ self.buffer = null;
+ self.sizeOfMessage = 0;
+ self.bytesRead = 0;
+ self.stubBuffer = null;
+
+ } else {
+
+ // Add the the bytes to the stub buffer
+ var newStubBuffer = new Buffer(self.stubBuffer.length + data.length);
+ // Copy existing stub buffer
+ self.stubBuffer.copy(newStubBuffer, 0);
+ // Copy missing part of the data
+ data.copy(newStubBuffer, self.stubBuffer.length);
+ // Exit parsing loop
+ data = new Buffer(0);
+ }
+ } else {
+ if(data.length > 4) {
+ // Retrieve the message size
+ var sizeOfMessage = binaryutils.decodeUInt32(data, 0);
+ // If we have a negative sizeOfMessage emit error and return
+ if(sizeOfMessage < 0 || sizeOfMessage > self.maxBsonSize) {
+ var errorObject = {err:"socketHandler", trace:'', bin:self.buffer, parseState:{
+ sizeOfMessage: sizeOfMessage,
+ bytesRead: self.bytesRead,
+ stubBuffer: self.stubBuffer}};
+ if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
+ // We got a parse Error fire it off then keep going
+ self.emit("parseError", errorObject, self);
+ return;
+ }
+
+ // Ensure that the size of message is larger than 0 and less than the max allowed
+ if(sizeOfMessage > 4 && sizeOfMessage < self.maxBsonSize && sizeOfMessage > data.length) {
+ self.buffer = new Buffer(sizeOfMessage);
+ // Copy all the data into the buffer
+ data.copy(self.buffer, 0);
+ // Update bytes read
+ self.bytesRead = data.length;
+ // Update sizeOfMessage
+ self.sizeOfMessage = sizeOfMessage;
+ // Ensure stub buffer is null
+ self.stubBuffer = null;
+ // Exit parsing loop
+ data = new Buffer(0);
+
+ } else if(sizeOfMessage > 4 && sizeOfMessage < self.maxBsonSize && sizeOfMessage == data.length) {
+ try {
+ var emitBuffer = data;
+ // Reset state of buffer
+ self.buffer = null;
+ self.sizeOfMessage = 0;
+ self.bytesRead = 0;
+ self.stubBuffer = null;
+ // Exit parsing loop
+ data = new Buffer(0);
+ // Emit the message
+ self.emit("message", emitBuffer, self);
+ } catch (err) {
+ var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{
+ sizeOfMessage:self.sizeOfMessage,
+ bytesRead:self.bytesRead,
+ stubBuffer:self.stubBuffer}};
+ if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
+ // We got a parse Error fire it off then keep going
+ self.emit("parseError", errorObject, self);
+ }
+ } else if(sizeOfMessage <= 4 || sizeOfMessage > self.maxBsonSize) {
+ var errorObject = {err:"socketHandler", trace:null, bin:data, parseState:{
+ sizeOfMessage:sizeOfMessage,
+ bytesRead:0,
+ buffer:null,
+ stubBuffer:null}};
+ if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
+ // We got a parse Error fire it off then keep going
+ self.emit("parseError", errorObject, self);
+
+ // Clear out the state of the parser
+ self.buffer = null;
+ self.sizeOfMessage = 0;
+ self.bytesRead = 0;
+ self.stubBuffer = null;
+ // Exit parsing loop
+ data = new Buffer(0);
+
+ } else {
+ try {
+ var emitBuffer = data.slice(0, sizeOfMessage);
+ // Reset state of buffer
+ self.buffer = null;
+ self.sizeOfMessage = 0;
+ self.bytesRead = 0;
+ self.stubBuffer = null;
+ // Copy rest of message
+ data = data.slice(sizeOfMessage);
+ // Emit the message
+ self.emit("message", emitBuffer, self);
+ } catch (err) {
+ var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{
+ sizeOfMessage:sizeOfMessage,
+ bytesRead:self.bytesRead,
+ stubBuffer:self.stubBuffer}};
+ if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
+ // We got a parse Error fire it off then keep going
+ self.emit("parseError", errorObject, self);
+ }
+
+ }
+ } else {
+ // Create a buffer that contains the space for the non-complete message
+ self.stubBuffer = new Buffer(data.length)
+ // Copy the data to the stub buffer
+ data.copy(self.stubBuffer, 0);
+ // Exit parsing loop
+ data = new Buffer(0);
+ }
+ }
+ }
+ }
+ }
+}
+
+var endHandler = function(self) {
+ return function() {
+ // Set connected to false
+ self.connected = false;
+ // Emit end event
+ self.emit("end", {err: 'connection received Fin packet from [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
+ }
+}
+
+var timeoutHandler = function(self) {
+ return function() {
+ // Set connected to false
+ self.connected = false;
+ // Emit timeout event
+ self.emit("timeout", {err: 'connection to [' + self.socketOptions.host + ':' + self.socketOptions.port + '] timed out'}, self);
+ }
+}
+
+var drainHandler = function(self) {
+ return function() {
+ }
+}
+
+var errorHandler = function(self) {
+ return function(err) {
+ self.connection.destroy();
+ // Set connected to false
+ self.connected = false;
+ // Emit error
+ self.emit("error", {err: 'failed to connect to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
+ }
+}
+
+var closeHandler = function(self) {
+ return function(hadError) {
+ // If we have an error during the connection phase
+ if(hadError && !self.connected) {
+ // Set disconnected
+ self.connected = false;
+ // Emit error
+ self.emit("error", {err: 'failed to connect to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
+ } else {
+ // Set disconnected
+ self.connected = false;
+ // Emit close
+ self.emit("close", {err: 'connection closed to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
+ }
+ }
+}
+
+// Some basic defaults
+Connection.DEFAULT_PORT = 27017;
+
+
+
+
+
+
+
diff --git a/node_modules/mongodb/lib/mongodb/connection/connection_pool.js b/node_modules/mongodb/lib/mongodb/connection/connection_pool.js
new file mode 100644
index 0000000..94cf754
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/connection_pool.js
@@ -0,0 +1,294 @@
+var utils = require('./connection_utils'),
+ inherits = require('util').inherits,
+ net = require('net'),
+ timers = require('timers'),
+ EventEmitter = require('events').EventEmitter,
+ inherits = require('util').inherits,
+ MongoReply = require("../responses/mongo_reply").MongoReply,
+ Connection = require("./connection").Connection;
+
+// Set processor, setImmediate if 0.10 otherwise nextTick
+var processor = timers.setImmediate ? timers.setImmediate : process.nextTick;
+processor = process.nextTick
+
+var ConnectionPool = exports.ConnectionPool = function(host, port, poolSize, bson, socketOptions) {
+ if(typeof host !== 'string') {
+ throw new Error("host must be specified [" + host + "]");
+ }
+
+ // Set up event emitter
+ EventEmitter.call(this);
+
+ // Keep all options for the socket in a specific collection allowing the user to specify the
+ // Wished upon socket connection parameters
+ this.socketOptions = typeof socketOptions === 'object' ? socketOptions : {};
+ this.socketOptions.host = host;
+ this.socketOptions.port = port;
+ this.socketOptions.domainSocket = false;
+ this.bson = bson;
+ // PoolSize is always + 1 for special reserved "measurment" socket (like ping, stats etc)
+ this.poolSize = poolSize;
+ this.minPoolSize = Math.floor(this.poolSize / 2) + 1;
+
+ // Check if the host is a socket
+ if(host.match(/^\//)) {
+ this.socketOptions.domainSocket = true;
+ } else if(typeof port === 'string') {
+ try {
+ port = parseInt(port, 10);
+ } catch(err) {
+ new Error("port must be specified or valid integer[" + port + "]");
+ }
+ } else if(typeof port !== 'number') {
+ throw new Error("port must be specified [" + port + "]");
+ }
+
+ // Set default settings for the socket options
+ utils.setIntegerParameter(this.socketOptions, 'timeout', 0);
+ // Delay before writing out the data to the server
+ utils.setBooleanParameter(this.socketOptions, 'noDelay', true);
+ // Delay before writing out the data to the server
+ utils.setIntegerParameter(this.socketOptions, 'keepAlive', 0);
+ // Set the encoding of the data read, default is binary == null
+ utils.setStringParameter(this.socketOptions, 'encoding', null);
+ // Allows you to set a throttling bufferSize if you need to stop overflows
+ utils.setIntegerParameter(this.socketOptions, 'bufferSize', 0);
+
+ // Internal structures
+ this.openConnections = [];
+ // Assign connection id's
+ this.connectionId = 0;
+
+ // Current index for selection of pool connection
+ this.currentConnectionIndex = 0;
+ // The pool state
+ this._poolState = 'disconnected';
+ // timeout control
+ this._timeout = false;
+ // Time to wait between connections for the pool
+ this._timeToWait = 10;
+}
+
+inherits(ConnectionPool, EventEmitter);
+
+ConnectionPool.prototype.setMaxBsonSize = function(maxBsonSize) {
+ if(maxBsonSize == null){
+ maxBsonSize = Connection.DEFAULT_MAX_BSON_SIZE;
+ }
+
+ for(var i = 0; i < this.openConnections.length; i++) {
+ this.openConnections[i].maxBsonSize = maxBsonSize;
+ }
+}
+
+ConnectionPool.prototype.setMaxMessageSizeBytes = function(maxMessageSizeBytes) {
+ if(maxMessageSizeBytes == null){
+ maxMessageSizeBytes = Connection.DEFAULT_MAX_MESSAGE_SIZE;
+ }
+
+ for(var i = 0; i < this.openConnections.length; i++) {
+ this.openConnections[i].maxMessageSizeBytes = maxMessageSizeBytes;
+ }
+}
+
+// Start a function
+var _connect = function(_self) {
+ // return new function() {
+ // Create a new connection instance
+ var connection = new Connection(_self.connectionId++, _self.socketOptions);
+ // Set logger on pool
+ connection.logger = _self.logger;
+ // Connect handler
+ connection.on("connect", function(err, connection) {
+ // Add connection to list of open connections
+ _self.openConnections.push(connection);
+ // If the number of open connections is equal to the poolSize signal ready pool
+ if(_self.openConnections.length === _self.poolSize && _self._poolState !== 'disconnected') {
+ // Set connected
+ _self._poolState = 'connected';
+ // Emit pool ready
+ _self.emit("poolReady");
+ } else if(_self.openConnections.length < _self.poolSize) {
+ // Wait a little bit of time to let the close event happen if the server closes the connection
+ // so we don't leave hanging connections around
+ if(typeof _self._timeToWait == 'number') {
+ setTimeout(function() {
+ // If we are still connecting (no close events fired in between start another connection)
+ if(_self._poolState == 'connecting') {
+ _connect(_self);
+ }
+ }, _self._timeToWait);
+ } else {
+ processor(function() {
+ // If we are still connecting (no close events fired in between start another connection)
+ if(_self._poolState == 'connecting') {
+ _connect(_self);
+ }
+ });
+ }
+ }
+ });
+
+ var numberOfErrors = 0
+
+ // Error handler
+ connection.on("error", function(err, connection, error_options) {
+ numberOfErrors++;
+ // If we are already disconnected ignore the event
+ if(_self._poolState != 'disconnected' && _self.listeners("error").length > 0) {
+ _self.emit("error", err, connection, error_options);
+ }
+
+ // Close the connection
+ connection.close();
+ // Set pool as disconnected
+ _self._poolState = 'disconnected';
+ // Stop the pool
+ _self.stop();
+ });
+
+ // Close handler
+ connection.on("close", function() {
+ // If we are already disconnected ignore the event
+ if(_self._poolState !== 'disconnected' && _self.listeners("close").length > 0) {
+ _self.emit("close");
+ }
+
+ // Set disconnected
+ _self._poolState = 'disconnected';
+ // Stop
+ _self.stop();
+ });
+
+ // Timeout handler
+ connection.on("timeout", function(err, connection) {
+ // If we are already disconnected ignore the event
+ if(_self._poolState !== 'disconnected' && _self.listeners("timeout").length > 0) {
+ _self.emit("timeout", err);
+ }
+
+ // Close the connection
+ connection.close();
+ // Set disconnected
+ _self._poolState = 'disconnected';
+ _self.stop();
+ });
+
+ // Parse error, needs a complete shutdown of the pool
+ connection.on("parseError", function() {
+ // If we are already disconnected ignore the event
+ if(_self._poolState !== 'disconnected' && _self.listeners("parseError").length > 0) {
+ _self.emit("parseError", new Error("parseError occured"));
+ }
+
+ // Set disconnected
+ _self._poolState = 'disconnected';
+ _self.stop();
+ });
+
+ connection.on("message", function(message) {
+ _self.emit("message", message);
+ });
+
+ // Start connection in the next tick
+ connection.start();
+ // }();
+}
+
+
+// Start method, will throw error if no listeners are available
+// Pass in an instance of the listener that contains the api for
+// finding callbacks for a given message etc.
+ConnectionPool.prototype.start = function() {
+ var markerDate = new Date().getTime();
+ var self = this;
+
+ if(this.listeners("poolReady").length == 0) {
+ throw "pool must have at least one listener ready that responds to the [poolReady] event";
+ }
+
+ // Set pool state to connecting
+ this._poolState = 'connecting';
+ this._timeout = false;
+
+ _connect(self);
+}
+
+// Restart a connection pool (on a close the pool might be in a wrong state)
+ConnectionPool.prototype.restart = function() {
+ // Close all connections
+ this.stop(false);
+ // Now restart the pool
+ this.start();
+}
+
+// Stop the connections in the pool
+ConnectionPool.prototype.stop = function(removeListeners) {
+ removeListeners = removeListeners == null ? true : removeListeners;
+ // Set disconnected
+ this._poolState = 'disconnected';
+
+ // Clear all listeners if specified
+ if(removeListeners) {
+ this.removeAllEventListeners();
+ }
+
+ // Close all connections
+ for(var i = 0; i < this.openConnections.length; i++) {
+ this.openConnections[i].close();
+ }
+
+ // Clean up
+ this.openConnections = [];
+}
+
+// Check the status of the connection
+ConnectionPool.prototype.isConnected = function() {
+ // return this._poolState === 'connected';
+ return this.openConnections.length > 0 && this.openConnections[0].isConnected();
+}
+
+// Checkout a connection from the pool for usage, or grab a specific pool instance
+ConnectionPool.prototype.checkoutConnection = function(id) {
+ var index = (this.currentConnectionIndex++ % (this.openConnections.length));
+ var connection = this.openConnections[index];
+ return connection;
+}
+
+ConnectionPool.prototype.getAllConnections = function() {
+ return this.openConnections;
+}
+
+// Remove all non-needed event listeners
+ConnectionPool.prototype.removeAllEventListeners = function() {
+ this.removeAllListeners("close");
+ this.removeAllListeners("error");
+ this.removeAllListeners("timeout");
+ this.removeAllListeners("connect");
+ this.removeAllListeners("end");
+ this.removeAllListeners("parseError");
+ this.removeAllListeners("message");
+ this.removeAllListeners("poolReady");
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/node_modules/mongodb/lib/mongodb/connection/connection_utils.js b/node_modules/mongodb/lib/mongodb/connection/connection_utils.js
new file mode 100644
index 0000000..5910924
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/connection_utils.js
@@ -0,0 +1,23 @@
+exports.setIntegerParameter = function(object, field, defaultValue) {
+ if(object[field] == null) {
+ object[field] = defaultValue;
+ } else if(typeof object[field] !== "number" && object[field] !== parseInt(object[field], 10)) {
+ throw "object field [" + field + "] must be a numeric integer value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
+ }
+}
+
+exports.setBooleanParameter = function(object, field, defaultValue) {
+ if(object[field] == null) {
+ object[field] = defaultValue;
+ } else if(typeof object[field] !== "boolean") {
+ throw "object field [" + field + "] must be a boolean value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
+ }
+}
+
+exports.setStringParameter = function(object, field, defaultValue) {
+ if(object[field] == null) {
+ object[field] = defaultValue;
+ } else if(typeof object[field] !== "string") {
+ throw "object field [" + field + "] must be a string value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
+ }
+}
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/connection/mongos.js b/node_modules/mongodb/lib/mongodb/connection/mongos.js
new file mode 100644
index 0000000..61a5bb1
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/mongos.js
@@ -0,0 +1,470 @@
+var ReadPreference = require('./read_preference').ReadPreference
+ , Base = require('./base').Base
+ , Server = require('./server').Server
+ , inherits = require('util').inherits;
+
+/**
+ * Mongos constructor provides a connection to a mongos proxy including failover to additional servers
+ *
+ * Options
+ * - **socketOptions** {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number))
+ * - **ha** {Boolean, default:true}, turn on high availability, attempts to reconnect to down proxies
+ * - **haInterval** {Number, default:2000}, time between each replicaset status check.
+ *
+ * @class Represents a Mongos connection with failover to backup proxies
+ * @param {Array} list of mongos server objects
+ * @param {Object} [options] additional options for the mongos connection
+ */
+var Mongos = function Mongos(servers, options) {
+ // Set up basic
+ if(!(this instanceof Mongos))
+ return new Mongos(servers, options);
+
+ // Set up event emitter
+ Base.call(this);
+
+ // Throw error on wrong setup
+ if(servers == null || !Array.isArray(servers) || servers.length == 0)
+ throw new Error("At least one mongos proxy must be in the array");
+
+ // Ensure we have at least an empty options object
+ this.options = options == null ? {} : options;
+ // Set default connection pool options
+ this.socketOptions = this.options.socketOptions != null ? this.options.socketOptions : {};
+ // Enabled ha
+ this.haEnabled = this.options['ha'] == null ? true : this.options['ha'];
+ this._haInProgress = false;
+ // How often are we checking for new servers in the replicaset
+ this.mongosStatusCheckInterval = this.options['haInterval'] == null ? 1000 : this.options['haInterval'];
+ // Save all the server connections
+ this.servers = servers;
+ // Servers we need to attempt reconnect with
+ this.downServers = [];
+ // Emit open setup
+ this.emitOpen = this.options.emitOpen || true;
+ // Just contains the current lowest ping time and server
+ this.lowestPingTimeServer = null;
+ this.lowestPingTime = 0;
+ // Connection timeout
+ this._connectTimeoutMS = this.socketOptions.connectTimeoutMS
+ ? this.socketOptions.connectTimeoutMS
+ : 1000;
+
+ // Add options to servers
+ for(var i = 0; i < this.servers.length; i++) {
+ var server = this.servers[i];
+ server._callBackStore = this._callBackStore;
+ server.auto_reconnect = false;
+ // Default empty socket options object
+ var socketOptions = {host: server.host, port: server.port};
+ // If a socket option object exists clone it
+ if(this.socketOptions != null) {
+ var keys = Object.keys(this.socketOptions);
+ for(var k = 0; k < keys.length;k++) socketOptions[keys[i]] = this.socketOptions[keys[i]];
+ }
+
+ // Set socket options
+ server.socketOptions = socketOptions;
+ }
+}
+
+/**
+ * @ignore
+ */
+inherits(Mongos, Base);
+
+/**
+ * @ignore
+ */
+Mongos.prototype.isMongos = function() {
+ return true;
+}
+
+/**
+ * @ignore
+ */
+Mongos.prototype.connect = function(db, options, callback) {
+ if('function' === typeof options) callback = options, options = {};
+ if(options == null) options = {};
+ if(!('function' === typeof callback)) callback = null;
+ var self = this;
+
+ // Keep reference to parent
+ this.db = db;
+ // Set server state to connecting
+ this._serverState = 'connecting';
+ // Number of total servers that need to initialized (known servers)
+ this._numberOfServersLeftToInitialize = this.servers.length;
+ // Connect handler
+ var connectHandler = function(_server) {
+ return function(err, result) {
+ self._numberOfServersLeftToInitialize = self._numberOfServersLeftToInitialize - 1;
+
+ if(self._numberOfServersLeftToInitialize == 0) {
+ // Start ha function if it exists
+ if(self.haEnabled) {
+ // Setup the ha process
+ if(self._replicasetTimeoutId != null) clearInterval(self._replicasetTimeoutId);
+ self._replicasetTimeoutId = setInterval(self.mongosCheckFunction, self.mongosStatusCheckInterval);
+ }
+
+ // Set the mongos to connected
+ self._serverState = "connected";
+
+ // Emit the open event
+ if(self.emitOpen)
+ self.db.emit("open", null, self.db);
+
+ // Callback
+ callback(null, self.db);
+ }
+ }
+ };
+
+ // Error handler
+ var errorOrCloseHandler = function(_server) {
+ return function(err, result) {
+ var validServers = [];
+ // Execute all the callbacks with errors
+ self.__executeAllCallbacksWithError(err);
+ // Check if we have the server
+ var found = false;
+ // Save the down server if it does not already exists
+ for(var i = 0; i < self.downServers.length; i++) {
+ if(self.downServers[i].host == _server.host && self.downServers[i].port == _server.port) {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)
+ self.downServers.push(_server);
+
+ // Remove the current server from the list
+ for(var i = 0; i < self.servers.length; i++) {
+ if(!(self.servers[i].host == _server.host && self.servers[i].port == _server.port) && self.servers[i].isConnected()) {
+ validServers.push(self.servers[i]);
+ }
+ }
+
+ // Set current list of servers
+ self.servers = validServers;
+
+ // Emit close across all the attached db instances
+ if(self.servers.length == 0) {
+ self._dbStore.emit("close", new Error("mongos disconnected, no valid proxies contactable over tcp"), null, true);
+ }
+ }
+ }
+
+ // Mongo function
+ this.mongosCheckFunction = function() {
+ if(self._haInProgress) return;
+ // If all servers are down we are done
+ if(self.servers.length == 0) return;
+
+ // Check that at least one server is available
+ var alldown = true;
+ for(var i = 0; i < self.servers.length; i++) {
+ if(self.servers[i].isConnected()) {
+ alldown = false;
+ break;
+ }
+ }
+
+ // All servers are down
+ if(alldown) return;
+
+ // Set as not waiting for check event
+ self._haInProgress = true;
+ // Check downed servers
+ if(self.downServers.length > 0) {
+ var numberOfServersLeft = self.downServers.length;
+
+ // Iterate over all the downed servers
+ for(var i = 0; i < self.downServers.length; i++) {
+ // Pop a downed server
+ var downServer = self.downServers.pop();
+
+ // Set up the connection options for a Mongos
+ var options = {
+ auto_reconnect: false,
+ returnIsMasterResults: true,
+ slaveOk: true,
+ poolSize: downServer.poolSize,
+ socketOptions: {
+ connectTimeoutMS: self._connectTimeoutMS,
+ socketTimeoutMS: self._socketTimeoutMS
+ }
+ }
+
+ // Create a new server object
+ var newServer = new Server(downServer.host, downServer.port, options);
+ // Setup the connection function
+ var connectFunction = function(_db, _server, _options, _callback) {
+ return function() {
+ // Attempt to connect
+ _server.connect(_db, _options, function(err, result) {
+ numberOfServersLeft = numberOfServersLeft - 1;
+
+ if(err) {
+ return _callback(err, _server);
+ } else {
+ // Set the new server settings
+ _server._callBackStore = self._callBackStore;
+
+ // Add server event handlers
+ _server.on("close", errorOrCloseHandler(_server));
+ _server.on("timeout", errorOrCloseHandler(_server));
+ _server.on("error", errorOrCloseHandler(_server));
+
+ // Get a read connection
+ var _connection = _server.checkoutReader();
+ // Get the start time
+ var startTime = new Date().getTime();
+
+ // Execute ping command to mark each server with the expected times
+ self.db.command({ping:1}
+ , {failFast:true, connection:_connection}, function(err, result) {
+ // Get the start time
+ var endTime = new Date().getTime();
+ // Mark the server with the ping time
+ _server.runtimeStats['pingMs'] = endTime - startTime;
+ // Sort the servers on runtime so the first server always is the closest one
+ self.servers.sort(function(a, b) {
+ return a.runtimeStats['pingMs'] > b.runtimeStats['pingMs'];
+ });
+
+ // Callback
+ return _callback(null, _server);
+ });
+ }
+ });
+ }
+ }
+
+ // Attempt to connect to the database
+ connectFunction(self.db, newServer, options, function(err, _server) {
+ // If we have an error
+ if(err) {
+ self.downServers.push(_server);
+ }
+
+ // Connection function
+ var connectionFunction = function(_auth, _connection, _callback) {
+ var pending = _auth.length();
+
+ for(var j = 0; j < pending; j++) {
+ // Get the auth object
+ var _auth = _auth.get(j);
+ // Unpack the parameter
+ var username = _auth.username;
+ var password = _auth.password;
+ var options = {
+ authMechanism: _auth.authMechanism
+ , authSource: _auth.authdb
+ , connection: _connection
+ };
+
+ // Hold any error
+ var _error = null;
+ // Authenticate against the credentials
+ self.db.authenticate(username, password, options, function(err, result) {
+ _error = err != null ? err : _error;
+ // Adjust the pending authentication
+ pending = pending - 1;
+ // Finished up
+ if(pending == 0) _callback(_error ? _error : null, _error ? false : true);
+ });
+ }
+ }
+
+ // Run auths against the connections
+ if(self.auth.length() > 0) {
+ var connections = _server.allRawConnections();
+ var pendingAuthConn = connections.length;
+
+ // No connections we are done
+ if(connections.length == 0) {
+ // Set ha done
+ if(numberOfServersLeft == 0) {
+ self._haInProgress = false;
+ }
+ }
+
+ // Final error object
+ var finalError = null;
+ // Go over all the connections
+ for(var j = 0; j < connections.length; j++) {
+
+ // Execute against all the connections
+ connectionFunction(self.auth, connections[j], function(err, result) {
+ // Pending authentication
+ pendingAuthConn = pendingAuthConn - 1 ;
+
+ // Save error if any
+ finalError = err ? err : finalError;
+
+ // If we are done let's finish up
+ if(pendingAuthConn == 0) {
+ // Set ha done
+ if(numberOfServersLeft == 0) {
+ self._haInProgress = false;
+ }
+
+ if(finalError) {
+ return self.downServers.push(_server);
+ }
+
+ // Push to list of valid server
+ self.servers.push(_server);
+ }
+ });
+ }
+ } else {
+ self.servers.push(_server);
+ // Set ha done
+ if(numberOfServersLeft == 0) {
+ self._haInProgress = false;
+ }
+ }
+ })();
+ }
+ } else {
+ self._haInProgress = false;
+ }
+ }
+
+ // Connect all the server instances
+ for(var i = 0; i < this.servers.length; i++) {
+ // Get the connection
+ var server = this.servers[i];
+ server.mongosInstance = this;
+ // Add server event handlers
+ server.on("close", errorOrCloseHandler(server));
+ server.on("timeout", errorOrCloseHandler(server));
+ server.on("error", errorOrCloseHandler(server));
+
+ // Configuration
+ var options = {
+ slaveOk: true,
+ poolSize: server.poolSize,
+ socketOptions: { connectTimeoutMS: self._connectTimeoutMS },
+ returnIsMasterResults: true
+ }
+
+ // Connect the instance
+ server.connect(self.db, options, connectHandler(server));
+ }
+}
+
+/**
+ * @ignore
+ * Just return the currently picked active connection
+ */
+Mongos.prototype.allServerInstances = function() {
+ return this.servers;
+}
+
+/**
+ * Always ourselves
+ * @ignore
+ */
+Mongos.prototype.setReadPreference = function() {}
+
+/**
+ * @ignore
+ */
+Mongos.prototype.allRawConnections = function() {
+ // Neeed to build a complete list of all raw connections, start with master server
+ var allConnections = [];
+ // Add all connections
+ for(var i = 0; i < this.servers.length; i++) {
+ allConnections = allConnections.concat(this.servers[i].allRawConnections());
+ }
+
+ // Return all the conections
+ return allConnections;
+}
+
+/**
+ * @ignore
+ */
+Mongos.prototype.isConnected = function() {
+ return this._serverState == "connected";
+}
+
+/**
+ * @ignore
+ */
+Mongos.prototype.canWrite = Mongos.prototype.isConnected;
+
+/**
+ * @ignore
+ */
+Mongos.prototype.canRead = Mongos.prototype.isConnected;
+
+/**
+ * @ignore
+ */
+Mongos.prototype.isDestroyed = function() {
+ return this._serverState == 'destroyed';
+}
+
+/**
+ * @ignore
+ */
+Mongos.prototype.checkoutWriter = function() {
+ if(this.servers.length == 0) return null;
+ return this.servers[0].checkoutWriter();
+}
+
+/**
+ * @ignore
+ */
+Mongos.prototype.checkoutReader = function(read) {
+ // If we have a read preference object unpack it
+ if(read != null && typeof read == 'object' && read['_type'] == 'ReadPreference') {
+ // Validate if the object is using a valid mode
+ if(!read.isValid()) throw new Error("Illegal readPreference mode specified, " + read.mode);
+ } else if(!ReadPreference.isValid(read)) {
+ throw new Error("Illegal readPreference mode specified, " + read);
+ }
+
+ if(this.servers.length == 0) return null;
+ return this.servers[0].checkoutWriter();
+}
+
+/**
+ * @ignore
+ */
+Mongos.prototype.close = function(callback) {
+ var self = this;
+ // Set server status as disconnected
+ this._serverState = 'destroyed';
+ // Number of connections to close
+ var numberOfConnectionsToClose = self.servers.length;
+ // If we have a ha process running kill it
+ if(self._replicasetTimeoutId != null) clearInterval(self._replicasetTimeoutId);
+ self._replicasetTimeoutId = null;
+ // Close all proxy connections
+ for(var i = 0; i < self.servers.length; i++) {
+ self.servers[i].close(function(err, result) {
+ numberOfConnectionsToClose = numberOfConnectionsToClose - 1;
+ // Callback if we have one defined
+ if(numberOfConnectionsToClose == 0 && typeof callback == 'function') {
+ callback(null);
+ }
+ });
+ }
+}
+
+/**
+ * @ignore
+ * Return the used state
+ */
+Mongos.prototype._isUsed = function() {
+ return this._used;
+}
+
+exports.Mongos = Mongos;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/connection/read_preference.js b/node_modules/mongodb/lib/mongodb/connection/read_preference.js
new file mode 100644
index 0000000..6845171
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/read_preference.js
@@ -0,0 +1,67 @@
+/**
+ * A class representation of the Read Preference.
+ *
+ * Read Preferences
+ * - **ReadPreference.PRIMARY**, Read from primary only. All operations produce an error (throw an exception where applicable) if primary is unavailable. Cannot be combined with tags (This is the default.).
+ * - **ReadPreference.PRIMARY_PREFERRED**, Read from primary if available, otherwise a secondary.
+ * - **ReadPreference.SECONDARY**, Read from secondary if available, otherwise error.
+ * - **ReadPreference.SECONDARY_PREFERRED**, Read from a secondary if available, otherwise read from the primary.
+ * - **ReadPreference.NEAREST**, All modes read from among the nearest candidates, but unlike other modes, NEAREST will include both the primary and all secondaries in the random selection.
+ *
+ * @class Represents a Read Preference.
+ * @param {String} the read preference type
+ * @param {Object} tags
+ * @return {ReadPreference}
+ */
+var ReadPreference = function(mode, tags) {
+ if(!(this instanceof ReadPreference))
+ return new ReadPreference(mode, tags);
+ this._type = 'ReadPreference';
+ this.mode = mode;
+ this.tags = tags;
+}
+
+/**
+ * @ignore
+ */
+ReadPreference.isValid = function(_mode) {
+ return (_mode == ReadPreference.PRIMARY || _mode == ReadPreference.PRIMARY_PREFERRED
+ || _mode == ReadPreference.SECONDARY || _mode == ReadPreference.SECONDARY_PREFERRED
+ || _mode == ReadPreference.NEAREST
+ || _mode == true || _mode == false);
+}
+
+/**
+ * @ignore
+ */
+ReadPreference.prototype.isValid = function(mode) {
+ var _mode = typeof mode == 'string' ? mode : this.mode;
+ return ReadPreference.isValid(_mode);
+}
+
+/**
+ * @ignore
+ */
+ReadPreference.prototype.toObject = function() {
+ var object = {mode:this.mode};
+
+ if(this.tags != null) {
+ object['tags'] = this.tags;
+ }
+
+ return object;
+}
+
+/**
+ * @ignore
+ */
+ReadPreference.PRIMARY = 'primary';
+ReadPreference.PRIMARY_PREFERRED = 'primaryPreferred';
+ReadPreference.SECONDARY = 'secondary';
+ReadPreference.SECONDARY_PREFERRED = 'secondaryPreferred';
+ReadPreference.NEAREST = 'nearest'
+
+/**
+ * @ignore
+ */
+exports.ReadPreference = ReadPreference;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/connection/repl_set/ha.js b/node_modules/mongodb/lib/mongodb/connection/repl_set/ha.js
new file mode 100644
index 0000000..f2b3717
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/repl_set/ha.js
@@ -0,0 +1,393 @@
+var DbCommand = require('../../commands/db_command').DbCommand
+ , format = require('util').format;
+
+var HighAvailabilityProcess = function(replset, options) {
+ this.replset = replset;
+ this.options = options;
+ this.server = null;
+ this.state = HighAvailabilityProcess.INIT;
+ this.selectedIndex = 0;
+}
+
+HighAvailabilityProcess.INIT = 'init';
+HighAvailabilityProcess.RUNNING = 'running';
+HighAvailabilityProcess.STOPPED = 'stopped';
+
+HighAvailabilityProcess.prototype.start = function() {
+ var self = this;
+ if(this.replset._state
+ && Object.keys(this.replset._state.addresses).length == 0) {
+ if(this.server) this.server.close();
+ this.state = HighAvailabilityProcess.STOPPED;
+ return;
+ }
+
+ if(this.server) this.server.close();
+ // Start the running
+ this._haProcessInProcess = false;
+ this.state = HighAvailabilityProcess.RUNNING;
+
+ // Get all possible reader servers
+ var candidate_servers = this.replset._state.getAllReadServers();
+ if(candidate_servers.length == 0) {
+ return;
+ }
+
+ // Select a candidate server for the connection
+ var server = candidate_servers[this.selectedIndex % candidate_servers.length];
+ this.selectedIndex = this.selectedIndex + 1;
+
+ // Unpack connection options
+ var connectTimeoutMS = self.options.connectTimeoutMS || 10000;
+ var socketTimeoutMS = self.options.socketTimeoutMS || 30000;
+
+ // Just ensure we don't have a full cycle dependency
+ var Db = require('../../db').Db
+ var Server = require('../server').Server;
+
+ // Set up a new server instance
+ var newServer = new Server(server.host, server.port, {
+ auto_reconnect: false
+ , returnIsMasterResults: true
+ , poolSize: 1
+ , socketOptions: {
+ connectTimeoutMS: connectTimeoutMS,
+ socketTimeoutMS: socketTimeoutMS,
+ keepAlive: 100
+ }
+ , ssl: this.options.ssl
+ , sslValidate: this.options.sslValidate
+ , sslCA: this.options.sslCA
+ , sslCert: this.options.sslCert
+ , sslKey: this.options.sslKey
+ , sslPass: this.options.sslPass
+ });
+
+ // Create new dummy db for app
+ self.db = new Db('local', newServer, {w:1});
+
+ // Set up the event listeners
+ newServer.once("error", _handle(this, newServer));
+ newServer.once("close", _handle(this, newServer));
+ newServer.once("timeout", _handle(this, newServer));
+ newServer.name = format("%s:%s", server.host, server.port);
+
+ // Let's attempt a connection over here
+ newServer.connect(self.db, function(err, result, _server) {
+ if(self.state == HighAvailabilityProcess.STOPPED) {
+ _server.close();
+ }
+
+ if(err) {
+ // Close the server
+ _server.close();
+ // Check if we can even do HA (is there anything running)
+ if(Object.keys(self.replset._state.addresses).length == 0) {
+ return;
+ }
+
+ // Let's boot the ha timeout settings
+ setTimeout(function() {
+ self.start();
+ }, self.options.haInterval);
+ } else {
+ self.server = _server;
+ // Let's boot the ha timeout settings
+ setTimeout(_timeoutHandle(self), self.options.haInterval);
+ }
+ });
+}
+
+HighAvailabilityProcess.prototype.stop = function() {
+ this.state = HighAvailabilityProcess.STOPPED;
+ if(this.server) this.server.close();
+}
+
+var _timeoutHandle = function(self) {
+ return function() {
+ if(self.state == HighAvailabilityProcess.STOPPED) {
+ // Stop all server instances
+ for(var name in self.replset._state.addresses) {
+ self.replset._state.addresses[name].close();
+ delete self.replset._state.addresses[name];
+ }
+
+ // Finished pinging
+ return;
+ }
+
+ // If the server is connected
+ if(self.server.isConnected() && !self._haProcessInProcess) {
+ // Start HA process
+ self._haProcessInProcess = true;
+ // Execute is master command
+ self.db._executeQueryCommand(DbCommand.createIsMasterCommand(self.db),
+ {failFast:true, connection: self.server.checkoutReader()}
+ , function(err, res) {
+ if(err) {
+ self.server.close();
+ return setTimeout(_timeoutHandle(self), self.options.haInterval);
+ }
+
+ // Master document
+ var master = res.documents[0];
+ var hosts = master.hosts || [];
+ var reconnect_servers = [];
+ var state = self.replset._state;
+
+ // For all the hosts let's check that we have connections
+ for(var i = 0; i < hosts.length; i++) {
+ var host = hosts[i];
+
+ // Check if we need to reconnect to a server
+ if(state.addresses[host] == null) {
+ reconnect_servers.push(host);
+ } else if(state.addresses[host] && !state.addresses[host].isConnected()) {
+ state.addresses[host].close();
+ reconnect_servers.push(host);
+ }
+
+ if((master.primary && state.master == null)
+ || (master.primary && state.master.name != master.primary)) {
+
+ // Locate the primary and set it
+ if(state.addresses[master.primary]) {
+ if(state.master) state.master.close();
+ delete state.secondaries[master.primary];
+ state.master = state.addresses[master.primary];
+ }
+
+ // Set up the changes
+ if(state.master != null && state.master.isMasterDoc != null) {
+ state.master.isMasterDoc.ismaster = true;
+ state.master.isMasterDoc.secondary = false;
+ } else if(state.master != null) {
+ state.master.isMasterDoc = master;
+ state.master.isMasterDoc.ismaster = true;
+ state.master.isMasterDoc.secondary = false;
+ }
+
+ // Execute any waiting commands (queries or writes)
+ self.replset._commandsStore.execute_queries();
+ self.replset._commandsStore.execute_writes();
+ }
+ }
+
+ // Let's reconnect to any server needed
+ if(reconnect_servers.length > 0) {
+ _reconnect_servers(self, reconnect_servers);
+ } else {
+ self._haProcessInProcess = false
+ return setTimeout(_timeoutHandle(self), self.options.haInterval);
+ }
+ });
+ } else if(!self.server.isConnected()) {
+ setTimeout(function() {
+ return self.start();
+ }, self.options.haInterval);
+ } else {
+ setTimeout(_timeoutHandle(self), self.options.haInterval);
+ }
+ }
+}
+
+var _reconnect_servers = function(self, reconnect_servers) {
+ if(reconnect_servers.length == 0) {
+ self._haProcessInProcess = false
+ return setTimeout(_timeoutHandle(self), self.options.haInterval);
+ }
+
+ // Unpack connection options
+ var connectTimeoutMS = self.options.connectTimeoutMS || 10000;
+ var socketTimeoutMS = self.options.socketTimeoutMS || 30000;
+
+ // Server class
+ var Db = require('../../db').Db
+ var Server = require('../server').Server;
+ // Get the host
+ var host = reconnect_servers.shift();
+ // Split it up
+ var _host = host.split(":")[0];
+ var _port = parseInt(host.split(":")[1], 10);
+
+ // Set up a new server instance
+ var newServer = new Server(_host, _port, {
+ auto_reconnect: false
+ , returnIsMasterResults: true
+ , poolSize: self.options.poolSize
+ , socketOptions: {
+ connectTimeoutMS: connectTimeoutMS,
+ socketTimeoutMS: socketTimeoutMS
+ }
+ , ssl: self.options.ssl
+ , sslValidate: self.options.sslValidate
+ , sslCA: self.options.sslCA
+ , sslCert: self.options.sslCert
+ , sslKey: self.options.sslKey
+ , sslPass: self.options.sslPass
+ });
+
+ // Create new dummy db for app
+ var db = new Db('local', newServer, {w:1});
+ var state = self.replset._state;
+
+ // Set up the event listeners
+ newServer.once("error", _repl_set_handler("error", self.replset, newServer));
+ newServer.once("close", _repl_set_handler("close", self.replset, newServer));
+ newServer.once("timeout", _repl_set_handler("timeout", self.replset, newServer));
+
+ // Set shared state
+ newServer.name = host;
+ newServer._callBackStore = self.replset._callBackStore;
+ newServer.replicasetInstance = self.replset;
+ newServer.enableRecordQueryStats(self.replset.recordQueryStats);
+
+ // Let's attempt a connection over here
+ newServer.connect(db, function(err, result, _server) {
+ if(self.state == HighAvailabilityProcess.STOPPED) {
+ _server.close();
+ }
+
+ // If we connected let's check what kind of server we have
+ if(!err) {
+ _apply_auths(self, db, _server, function(err, result) {
+ if(err) {
+ _server.close();
+ // Process the next server
+ return setTimeout(function() {
+ _reconnect_servers(self, reconnect_servers);
+ }, self.options.haInterval);
+ }
+ var doc = _server.isMasterDoc;
+ // Fire error on any unknown callbacks for this server
+ self.replset.__executeAllServerSpecificErrorCallbacks(_server.socketOptions.host, _server.socketOptions.port, err);
+
+ if(doc.ismaster) {
+ if(state.secondaries[doc.me]) {
+ delete state.secondaries[doc.me];
+ }
+
+ // Override any server in list of addresses
+ state.addresses[doc.me] = _server;
+ // Set server as master
+ state.master = _server;
+ // Execute any waiting writes
+ self.replset._commandsStore.execute_writes();
+ } else if(doc.secondary) {
+ state.secondaries[doc.me] = _server;
+ // Override any server in list of addresses
+ state.addresses[doc.me] = _server;
+ // Execute any waiting reads
+ self.replset._commandsStore.execute_queries();
+ } else {
+ _server.close();
+ }
+
+ // Set any tags on the instance server
+ _server.name = doc.me;
+ _server.tags = doc.tags;
+ // Process the next server
+ setTimeout(function() {
+ _reconnect_servers(self, reconnect_servers);
+ }, self.options.haInterval);
+ });
+ } else {
+ _server.close();
+ self.replset.__executeAllServerSpecificErrorCallbacks(_server.socketOptions.host, _server.socketOptions.port, err);
+
+ setTimeout(function() {
+ _reconnect_servers(self, reconnect_servers);
+ }, self.options.haInterval);
+ }
+ });
+}
+
+var _apply_auths = function(self, _db, _server, _callback) {
+ if(self.replset.auth.length() == 0) return _callback(null);
+ // Apply any authentication needed
+ if(self.replset.auth.length() > 0) {
+ var pending = self.replset.auth.length();
+ var connections = _server.allRawConnections();
+ var pendingAuthConn = connections.length;
+
+ // Connection function
+ var connectionFunction = function(_auth, _connection, __callback) {
+ var pending = _auth.length();
+
+ for(var j = 0; j < pending; j++) {
+ // Get the auth object
+ var _auth = _auth.get(j);
+ // Unpack the parameter
+ var username = _auth.username;
+ var password = _auth.password;
+ var options = {
+ authMechanism: _auth.authMechanism
+ , authSource: _auth.authdb
+ , connection: _connection
+ };
+
+ // Hold any error
+ var _error = null;
+
+ // Authenticate against the credentials
+ _db.authenticate(username, password, options, function(err, result) {
+ _error = err != null ? err : _error;
+ // Adjust the pending authentication
+ pending = pending - 1;
+ // Finished up
+ if(pending == 0) __callback(_error ? _error : null, _error ? false : true);
+ });
+ }
+ }
+
+ // Final error object
+ var finalError = null;
+ // Iterate over all the connections
+ for(var i = 0; i < connections.length; i++) {
+ connectionFunction(self.replset.auth, connections[i], function(err, result) {
+ // Pending authentication
+ pendingAuthConn = pendingAuthConn - 1 ;
+
+ // Save error if any
+ finalError = err ? err : finalError;
+
+ // If we are done let's finish up
+ if(pendingAuthConn == 0) {
+ _callback(null);
+ }
+ });
+ }
+ }
+}
+
+var _handle = function(self, server) {
+ return function(err) {
+ server.close();
+ }
+}
+
+var _repl_set_handler = function(event, self, server) {
+ var ReplSet = require('./repl_set').ReplSet;
+
+ return function(err, doc) {
+ server.close();
+
+ // The event happened to a primary
+ // Remove it from play
+ if(self._state.isPrimary(server)) {
+ self._state.master == null;
+ self._serverState = ReplSet.REPLSET_READ_ONLY;
+ } else if(self._state.isSecondary(server)) {
+ delete self._state.secondaries[server.name];
+ }
+
+ // Unpack variables
+ var host = server.socketOptions.host;
+ var port = server.socketOptions.port;
+
+ // Fire error on any unknown callbacks
+ self.__executeAllServerSpecificErrorCallbacks(host, port, err);
+ }
+}
+
+exports.HighAvailabilityProcess = HighAvailabilityProcess;
diff --git a/node_modules/mongodb/lib/mongodb/connection/repl_set/options.js b/node_modules/mongodb/lib/mongodb/connection/repl_set/options.js
new file mode 100644
index 0000000..a5658e3
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/repl_set/options.js
@@ -0,0 +1,126 @@
+var PingStrategy = require('./strategies/ping_strategy').PingStrategy
+ , StatisticsStrategy = require('./strategies/statistics_strategy').StatisticsStrategy
+ , ReadPreference = require('../read_preference').ReadPreference;
+
+var Options = function(options) {
+ options = options || {};
+ this._options = options;
+ this.ha = options.ha || true;
+ this.haInterval = options.haInterval || 2000;
+ this.reconnectWait = options.reconnectWait || 1000;
+ this.retries = options.retries || 30;
+ this.rs_name = options.rs_name;
+ this.socketOptions = options.socketOptions || {};
+ this.readPreference = options.readPreference;
+ this.readSecondary = options.read_secondary;
+ this.poolSize = options.poolSize == null ? 5 : options.poolSize;
+ this.strategy = options.strategy || 'ping';
+ this.secondaryAcceptableLatencyMS = options.secondaryAcceptableLatencyMS || 15;
+ this.connectArbiter = options.connectArbiter || false;
+ this.connectWithNoPrimary = options.connectWithNoPrimary || false;
+ this.logger = options.logger;
+ this.ssl = options.ssl || false;
+ this.sslValidate = options.sslValidate || false;
+ this.sslCA = options.sslCA;
+ this.sslCert = options.sslCert;
+ this.sslKey = options.sslKey;
+ this.sslPass = options.sslPass;
+ this.emitOpen = options.emitOpen || true;
+}
+
+Options.prototype.init = function() {
+ if(this.sslValidate && (!Array.isArray(this.sslCA) || this.sslCA.length == 0)) {
+ throw new Error("The driver expects an Array of CA certificates in the sslCA parameter when enabling sslValidate");
+ }
+
+ // Make sure strategy is one of the two allowed
+ if(this.strategy != null && (this.strategy != 'ping' && this.strategy != 'statistical' && this.strategy != 'none'))
+ throw new Error("Only ping or statistical strategies allowed");
+
+ if(this.strategy == null) this.strategy = 'ping';
+
+ // Set logger if strategy exists
+ if(this.strategyInstance) this.strategyInstance.logger = this.logger;
+
+ // Unpack read Preference
+ var readPreference = this.readPreference;
+ // Validate correctness of Read preferences
+ if(readPreference != null) {
+ if(readPreference != ReadPreference.PRIMARY && readPreference != ReadPreference.PRIMARY_PREFERRED
+ && readPreference != ReadPreference.SECONDARY && readPreference != ReadPreference.SECONDARY_PREFERRED
+ && readPreference != ReadPreference.NEAREST && typeof readPreference != 'object' && readPreference['_type'] != 'ReadPreference') {
+ throw new Error("Illegal readPreference mode specified, " + readPreference);
+ }
+
+ this.readPreference = readPreference;
+ } else {
+ this.readPreference = null;
+ }
+
+ // Ensure read_secondary is set correctly
+ if(this.readSecondary != null)
+ this.readSecondary = this.readPreference == ReadPreference.PRIMARY
+ || this.readPreference == false
+ || this.readPreference == null ? false : true;
+
+ // Ensure correct slave set
+ if(this.readSecondary) this.slaveOk = true;
+
+ // Set up logger if any set
+ this.logger = this.logger != null
+ && (typeof this.logger.debug == 'function')
+ && (typeof this.logger.error == 'function')
+ && (typeof this.logger.debug == 'function')
+ ? this.logger : {error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}};
+
+ // Connection timeout
+ this.connectTimeoutMS = this.socketOptions.connectTimeoutMS
+ ? this.socketOptions.connectTimeoutMS
+ : 1000;
+
+ // Socket connection timeout
+ this.socketTimeoutMS = this.socketOptions.socketTimeoutMS
+ ? this.socketOptions.socketTimeoutMS
+ : 30000;
+}
+
+Options.prototype.decorateAndClean = function(servers, callBackStore) {
+ var self = this;
+
+ // var de duplicate list
+ var uniqueServers = {};
+ // De-duplicate any servers in the seed list
+ for(var i = 0; i < servers.length; i++) {
+ var server = servers[i];
+ // If server does not exist set it
+ if(uniqueServers[server.host + ":" + server.port] == null) {
+ uniqueServers[server.host + ":" + server.port] = server;
+ }
+ }
+
+ // Let's set the deduplicated list of servers
+ var finalServers = [];
+ // Add the servers
+ for(var key in uniqueServers) {
+ finalServers.push(uniqueServers[key]);
+ }
+
+ finalServers.forEach(function(server) {
+ // Ensure no server has reconnect on
+ server.options.auto_reconnect = false;
+ // Set up ssl options
+ server.ssl = self.ssl;
+ server.sslValidate = self.sslValidate;
+ server.sslCA = self.sslCA;
+ server.sslCert = self.sslCert;
+ server.sslKey = self.sslKey;
+ server.sslPass = self.sslPass;
+ server.poolSize = self.poolSize;
+ // Set callback store
+ server._callBackStore = callBackStore;
+ });
+
+ return finalServers;
+}
+
+exports.Options = Options;
diff --git a/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set.js b/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set.js
new file mode 100644
index 0000000..d11867b
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set.js
@@ -0,0 +1,763 @@
+var ReadPreference = require('../read_preference').ReadPreference
+ , DbCommand = require('../../commands/db_command').DbCommand
+ , inherits = require('util').inherits
+ , format = require('util').format
+ , timers = require('timers')
+ , Server = require('../server').Server
+ , utils = require('../../utils')
+ , PingStrategy = require('./strategies/ping_strategy').PingStrategy
+ , StatisticsStrategy = require('./strategies/statistics_strategy').StatisticsStrategy
+ , Options = require('./options').Options
+ , ReplSetState = require('./repl_set_state').ReplSetState
+ , HighAvailabilityProcess = require('./ha').HighAvailabilityProcess
+ , Base = require('../base').Base;
+
+const STATE_STARTING_PHASE_1 = 0;
+const STATE_PRIMARY = 1;
+const STATE_SECONDARY = 2;
+const STATE_RECOVERING = 3;
+const STATE_FATAL_ERROR = 4;
+const STATE_STARTING_PHASE_2 = 5;
+const STATE_UNKNOWN = 6;
+const STATE_ARBITER = 7;
+const STATE_DOWN = 8;
+const STATE_ROLLBACK = 9;
+
+// Set processor, setImmediate if 0.10 otherwise nextTick
+var processor = timers.setImmediate ? timers.setImmediate : process.nextTick;
+
+/**
+ * ReplSet constructor provides replicaset functionality
+ *
+ * Options
+ * - **ha** {Boolean, default:true}, turn on high availability.
+ * - **haInterval** {Number, default:2000}, time between each replicaset status check.
+ * - **reconnectWait** {Number, default:1000}, time to wait in miliseconds before attempting reconnect.
+ * - **retries** {Number, default:30}, number of times to attempt a replicaset reconnect.
+ * - **rs_name** {String}, the name of the replicaset to connect to.
+ * - **socketOptions** {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number))
+ * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * - **strategy** {String, default:'ping'}, selection strategy for reads choose between (ping, statistical and none, default is ping)
+ * - **secondaryAcceptableLatencyMS** {Number, default:15}, sets the range of servers to pick when using NEAREST (lowest ping ms + the latency fence, ex: range of 1 to (1 + 15) ms)
+ * - **connectWithNoPrimary** {Boolean, default:false}, sets if the driver should connect even if no primary is available
+ * - **connectArbiter** {Boolean, default:false}, sets if the driver should connect to arbiters or not.
+ * - **logger** {Object, default:null}, an object representing a logger that you want to use, needs to support functions debug, log, error **({error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}})**.
+ * - **poolSize** {Number, default:5}, number of connections in the connection pool for each server instance, set to 5 as default for legacy reasons.
+ * - **ssl** {Boolean, default:false}, use ssl connection (needs to have a mongod server with ssl support)
+ * - **sslValidate** {Boolean, default:false}, validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher)
+ * - **sslCA** {Array, default:null}, Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
+ * - **sslCert** {Buffer/String, default:null}, String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
+ * - **sslKey** {Buffer/String, default:null}, String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
+ * - **sslPass** {Buffer/String, default:null}, String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher)
+ *
+ * @class Represents a Replicaset Configuration
+ * @param {Array} list of server objects participating in the replicaset.
+ * @param {Object} [options] additional options for the replicaset connection.
+ */
+var ReplSet = exports.ReplSet = function(servers, options) {
+ // Set up basic
+ if(!(this instanceof ReplSet))
+ return new ReplSet(servers, options);
+
+ // Set up event emitter
+ Base.call(this);
+
+ // Ensure we have a list of servers
+ if(!Array.isArray(servers)) throw Error("The parameter must be an array of servers and contain at least one server");
+ // Ensure no Mongos's
+ for(var i = 0; i < servers.length; i++) {
+ if(!(servers[i] instanceof Server)) throw new Error("list of servers must be of type Server");
+ }
+
+ // Save the options
+ this.options = new Options(options);
+ // Ensure basic validation of options
+ this.options.init();
+
+ // Server state
+ this._serverState = ReplSet.REPLSET_DISCONNECTED;
+ // Add high availability process
+ this._haProcess = new HighAvailabilityProcess(this, this.options);
+
+
+ // Let's iterate over all the provided server objects and decorate them
+ this.servers = this.options.decorateAndClean(servers, this._callBackStore);
+ // Throw error if no seed servers
+ if(this.servers.length == 0) throw new Error("No valid seed servers in the array");
+
+ // Let's set up our strategy object for picking secondaries
+ if(this.options.strategy == 'ping') {
+ // Create a new instance
+ this.strategyInstance = new PingStrategy(this, this.options.secondaryAcceptableLatencyMS);
+ } else if(this.options.strategy == 'statistical') {
+ // Set strategy as statistical
+ this.strategyInstance = new StatisticsStrategy(this);
+ // Add enable query information
+ this.enableRecordQueryStats(true);
+ }
+
+ this.emitOpen = this.options.emitOpen || true;
+ // Set up a clean state
+ this._state = new ReplSetState();
+ // Ensure up the server callbacks
+ for(var i = 0; i < this.servers.length; i++) {
+ this.servers[i]._callBackStore = this._callBackStore;
+ this.servers[i].name = format("%s:%s", this.servers[i].host, this.servers[i].port)
+ this.servers[i].replicasetInstance = this;
+ this.servers[i].options.auto_reconnect = false;
+ this.servers[i].inheritReplSetOptionsFrom(this);
+ }
+}
+
+/**
+ * @ignore
+ */
+inherits(ReplSet, Base);
+
+// Replicaset states
+ReplSet.REPLSET_CONNECTING = 'connecting';
+ReplSet.REPLSET_DISCONNECTED = 'disconnected';
+ReplSet.REPLSET_CONNECTED = 'connected';
+ReplSet.REPLSET_RECONNECTING = 'reconnecting';
+ReplSet.REPLSET_DESTROYED = 'destroyed';
+ReplSet.REPLSET_READ_ONLY = 'readonly';
+
+ReplSet.prototype.isAutoReconnect = function() {
+ return true;
+}
+
+ReplSet.prototype.canWrite = function() {
+ return this._state.master && this._state.master.isConnected();
+}
+
+ReplSet.prototype.canRead = function(read) {
+ if((read == ReadPreference.PRIMARY
+ || read == null || read == false) && (this._state.master == null || !this._state.master.isConnected())) return false;
+ return Object.keys(this._state.secondaries).length > 0;
+}
+
+/**
+ * @ignore
+ */
+ReplSet.prototype.enableRecordQueryStats = function(enable) {
+ // Set the global enable record query stats
+ this.recordQueryStats = enable;
+
+ // Enable all the servers
+ for(var i = 0; i < this.servers.length; i++) {
+ this.servers[i].enableRecordQueryStats(enable);
+ }
+}
+
+/**
+ * @ignore
+ */
+ReplSet.prototype.setReadPreference = function(preference) {
+ this.options.readPreference = preference;
+}
+
+ReplSet.prototype.connect = function(parent, options, callback) {
+ if(this._serverState != ReplSet.REPLSET_DISCONNECTED)
+ return callback(new Error("in process of connection"));
+
+ // If no callback throw
+ if(!(typeof callback == 'function'))
+ throw new Error("cannot call ReplSet.prototype.connect with no callback function");
+
+ var self = this;
+ // Save db reference
+ this.options.db = parent;
+ // Set replicaset as connecting
+ this._serverState = ReplSet.REPLSET_CONNECTING
+ // Copy all the servers to our list of seeds
+ var candidateServers = this.servers.slice(0);
+ // Pop the first server
+ var server = candidateServers.pop();
+ server.name = format("%s:%s", server.host, server.port);
+ // Set up the options
+ var opts = {
+ returnIsMasterResults: true,
+ eventReceiver: server
+ }
+
+ // Register some event listeners
+ this.once("fullsetup", function(err, db, replset) {
+ // Set state to connected
+ self._serverState = ReplSet.REPLSET_CONNECTED;
+ // Stop any process running
+ if(self._haProcess) self._haProcess.stop();
+ // Start the HA process
+ self._haProcess.start();
+
+ // Emit fullsetup
+ processor(function() {
+ if(self.emitOpen)
+ parent.emit("open", null, self.options.db, self);
+
+ parent.emit("fullsetup", null, self.options.db, self);
+ });
+
+ // If we have a strategy defined start it
+ if(self.strategyInstance) {
+ self.strategyInstance.start();
+ }
+
+ // Finishing up the call
+ callback(err, db, replset);
+ });
+
+ // Errors
+ this.once("connectionError", function(err, result) {
+ callback(err, result);
+ });
+
+ // Attempt to connect to the server
+ server.connect(this.options.db, opts, _connectHandler(this, candidateServers, server));
+}
+
+ReplSet.prototype.close = function(callback) {
+ var self = this;
+ // Set as destroyed
+ this._serverState = ReplSet.REPLSET_DESTROYED;
+ // Stop the ha
+ this._haProcess.stop();
+
+ // If we have a strategy stop it
+ if(this.strategyInstance) {
+ this.strategyInstance.stop();
+ }
+
+ // Kill all servers available
+ for(var name in this._state.addresses) {
+ this._state.addresses[name].close();
+ }
+
+ // Clean out the state
+ this._state = new ReplSetState();
+
+ // Emit close event
+ processor(function() {
+ self._emitAcrossAllDbInstances(self, null, "close", null, null, true)
+ });
+
+ // Callback
+ if(typeof callback == 'function')
+ return callback(null, null);
+}
+
+/**
+ * Creates a new server for the `replset` based on `host`.
+ *
+ * @param {String} host - host:port pair (localhost:27017)
+ * @param {ReplSet} replset - the ReplSet instance
+ * @return {Server}
+ * @ignore
+ */
+var createServer = function(self, host, options) {
+ // copy existing socket options to new server
+ var socketOptions = {}
+ if(options.socketOptions) {
+ var keys = Object.keys(options.socketOptions);
+ for(var k = 0; k < keys.length; k++) {
+ socketOptions[keys[k]] = options.socketOptions[keys[k]];
+ }
+ }
+
+ var parts = host.split(/:/);
+ if(1 === parts.length) {
+ parts[1] = Connection.DEFAULT_PORT;
+ }
+
+ socketOptions.host = parts[0];
+ socketOptions.port = parseInt(parts[1], 10);
+
+ var serverOptions = {
+ readPreference: options.readPreference,
+ socketOptions: socketOptions,
+ poolSize: options.poolSize,
+ logger: options.logger,
+ auto_reconnect: false,
+ ssl: options.ssl,
+ sslValidate: options.sslValidate,
+ sslCA: options.sslCA,
+ sslCert: options.sslCert,
+ sslKey: options.sslKey,
+ sslPass: options.sslPass
+ }
+
+ var server = new Server(socketOptions.host, socketOptions.port, serverOptions);
+ // Set up shared state
+ server._callBackStore = self._callBackStore;
+ server.replicasetInstance = self;
+ server.enableRecordQueryStats(self.recordQueryStats);
+ // Set up event handlers
+ server.on("close", _handler("close", self, server));
+ server.on("error", _handler("error", self, server));
+ server.on("timeout", _handler("timeout", self, server));
+ return server;
+}
+
+var _handler = function(event, self, server) {
+ return function(err, doc) {
+ // The event happened to a primary
+ // Remove it from play
+ if(self._state.isPrimary(server)) {
+ var current_master = self._state.master;
+ self._state.master = null;
+ self._serverState = ReplSet.REPLSET_READ_ONLY;
+
+ if(current_master != null) {
+ // Unpack variables
+ var host = current_master.socketOptions.host;
+ var port = current_master.socketOptions.port;
+
+ // Fire error on any unknown callbacks
+ self.__executeAllServerSpecificErrorCallbacks(host, port, err);
+ }
+ } else if(self._state.isSecondary(server)) {
+ delete self._state.secondaries[server.name];
+ }
+
+ // If there is no more connections left and the setting is not destroyed
+ // set to disconnected
+ if(Object.keys(self._state.addresses).length == 0
+ && self._serverState != ReplSet.REPLSET_DESTROYED) {
+ self._serverState = ReplSet.REPLSET_DISCONNECTED;
+
+ // Emit close across all the attached db instances
+ self._dbStore.emit("close", new Error("replicaset disconnected, no valid servers contactable over tcp"), null, true);
+ }
+
+ // Unpack variables
+ var host = server.socketOptions.host;
+ var port = server.socketOptions.port;
+
+ // Fire error on any unknown callbacks
+ self.__executeAllServerSpecificErrorCallbacks(host, port, err);
+ }
+}
+
+var locateNewServers = function(self, state, candidateServers, ismaster) {
+ // Retrieve the host
+ var hosts = ismaster.hosts;
+ // In candidate servers
+ var inCandidateServers = function(name, candidateServers) {
+ for(var i = 0; i < candidateServers.length; i++) {
+ if(candidateServers[i].name == name) return true;
+ }
+
+ return false;
+ }
+
+ // New servers
+ var newServers = [];
+ if(Array.isArray(hosts)) {
+ // Let's go over all the hosts
+ for(var i = 0; i < hosts.length; i++) {
+ if(!state.contains(hosts[i])
+ && !inCandidateServers(hosts[i], candidateServers)) {
+ newServers.push(createServer(self, hosts[i], self.options));
+ }
+ }
+ }
+
+ // Return list of possible new servers
+ return newServers;
+}
+
+var _connectHandler = function(self, candidateServers, instanceServer) {
+ return function(err, doc) {
+ // If we have an error add to the list
+ if(err) self._state.errors[instanceServer.name] = instanceServer;
+
+ // No error let's analyse the ismaster command
+ if(!err) {
+ var ismaster = doc.documents[0]
+ // console.dir(ismaster)
+ // If no replicaset name exists set the current one
+ if(self.options.rs_name == null) {
+ self.options.rs_name = ismaster.setName;
+ }
+
+ // If we have a member that is not part of the set let's finish up
+ if(typeof ismaster.setName == 'string' && ismaster.setName != self.options.rs_name) {
+ return self.emit("connectionError", new Error("Replicaset name " + ismaster.setName + " does not match specified name " + self.options.rs_name));
+ }
+
+ // Add the error handlers
+ instanceServer.on("close", _handler("close", self, instanceServer));
+ instanceServer.on("error", _handler("error", self, instanceServer));
+ instanceServer.on("timeout", _handler("timeout", self, instanceServer));
+
+ // Set any tags on the instance server
+ instanceServer.name = ismaster.me;
+ instanceServer.tags = ismaster.tags;
+
+ // Add the server to the list
+ self._state.addServer(instanceServer, ismaster);
+
+ // Check if we have more servers to add (only check when done with initial set)
+ if(candidateServers.length == 0) {
+ // Get additional new servers that are not currently in set
+ var new_servers = locateNewServers(self, self._state, candidateServers, ismaster);
+
+ // If we have new servers join them
+ if(new_servers.length > 0) {
+ candidateServers = candidateServers.concat(new_servers);
+ }
+ }
+ }
+
+ // If the candidate server list is empty and no valid servers
+ if(candidateServers.length == 0 &&
+ !self._state.hasValidServers()) {
+ return self.emit("connectionError", new Error("No valid replicaset instance servers found"));
+ } else if(candidateServers.length == 0) {
+ if(!self.options.connectWithNoPrimary && (self._state.master == null || !self._state.master.isConnected())) {
+ return self.emit("connectionError", new Error("No primary found in set"));
+ }
+ return self.emit("fullsetup", null, self.options.db, self);
+ }
+
+ // Let's connect the next server
+ var nextServer = candidateServers.pop();
+
+ // Set up the options
+ var opts = {
+ returnIsMasterResults: true,
+ eventReceiver: nextServer
+ }
+
+ // Attempt to connect to the server
+ nextServer.connect(self.options.db, opts, _connectHandler(self, candidateServers, nextServer));
+ }
+}
+
+ReplSet.prototype.isDestroyed = function() {
+ return this._serverState == ReplSet.REPLSET_DESTROYED;
+}
+
+ReplSet.prototype.isConnected = function(read) {
+ var isConnected = false;
+
+ if(read == null || read == ReadPreference.PRIMARY || read == false)
+ isConnected = this._state.master != null && this._state.master.isConnected();
+
+ if((read == ReadPreference.PRIMARY_PREFERRED || read == ReadPreference.SECONDARY_PREFERRED || read == ReadPreference.NEAREST)
+ && ((this._state.master != null && this._state.master.isConnected())
+ || (this._state && this._state.secondaries && Object.keys(this._state.secondaries).length > 0))) {
+ isConnected = true;
+ } else if(read == ReadPreference.SECONDARY) {
+ isConnected = this._state && this._state.secondaries && Object.keys(this._state.secondaries).length > 0;
+ }
+
+ // No valid connection return false
+ return isConnected;
+}
+
+ReplSet.prototype.isMongos = function() {
+ return false;
+}
+
+ReplSet.prototype.checkoutWriter = function() {
+ if(this._state.master) return this._state.master.checkoutWriter();
+ return new Error("no writer connection available");
+}
+
+ReplSet.prototype.allRawConnections = function() {
+ var connections = [];
+
+ for(var name in this._state.addresses) {
+ connections = connections.concat(this._state.addresses[name].allRawConnections());
+ }
+
+ return connections;
+}
+
+/**
+ * @ignore
+ */
+ReplSet.prototype.allServerInstances = function() {
+ var self = this;
+ // If no state yet return empty
+ if(!self._state) return [];
+ // Close all the servers (concatenate entire list of servers first for ease)
+ var allServers = self._state.master != null ? [self._state.master] : [];
+
+ // Secondary keys
+ var keys = Object.keys(self._state.secondaries);
+ // Add all secondaries
+ for(var i = 0; i < keys.length; i++) {
+ allServers.push(self._state.secondaries[keys[i]]);
+ }
+
+ // Return complete list of all servers
+ return allServers;
+}
+
+/**
+ * @ignore
+ */
+ReplSet.prototype.checkoutReader = function(readPreference, tags) {
+ var connection = null;
+
+ // If we have a read preference object unpack it
+ if(typeof readPreference == 'object' && readPreference['_type'] == 'ReadPreference') {
+ // Validate if the object is using a valid mode
+ if(!readPreference.isValid()) throw new Error("Illegal readPreference mode specified, " + readPreference.mode);
+ // Set the tag
+ tags = readPreference.tags;
+ readPreference = readPreference.mode;
+ } else if(typeof readPreference == 'object' && readPreference['_type'] != 'ReadPreference') {
+ return new Error("read preferences must be either a string or an instance of ReadPreference");
+ }
+
+ // Set up our read Preference, allowing us to override the readPreference
+ var finalReadPreference = readPreference != null ? readPreference : this.options.readPreference;
+
+ // Ensure we unpack a reference
+ if(finalReadPreference != null && typeof finalReadPreference == 'object' && finalReadPreference['_type'] == 'ReadPreference') {
+ // Validate if the object is using a valid mode
+ if(!finalReadPreference.isValid()) throw new Error("Illegal readPreference mode specified, " + finalReadPreference.mode);
+ // Set the tag
+ tags = finalReadPreference.tags;
+ readPreference = finalReadPreference.mode;
+ }
+
+ // Finalize the read preference setup
+ finalReadPreference = finalReadPreference == true ? ReadPreference.SECONDARY_PREFERRED : finalReadPreference;
+ finalReadPreference = finalReadPreference == null ? ReadPreference.PRIMARY : finalReadPreference;
+
+ // If we are reading from a primary
+ if(finalReadPreference == 'primary') {
+ // If we provide a tags set send an error
+ if(typeof tags == 'object' && tags != null) {
+ return new Error("PRIMARY cannot be combined with tags");
+ }
+
+ // If we provide a tags set send an error
+ if(this._state.master == null) {
+ return new Error("No replica set primary available for query with ReadPreference PRIMARY");
+ }
+
+ // Checkout a writer
+ return this.checkoutWriter();
+ }
+
+ // If we have specified to read from a secondary server grab a random one and read
+ // from it, otherwise just pass the primary connection
+ if((this.options.readSecondary || finalReadPreference == ReadPreference.SECONDARY_PREFERRED || finalReadPreference == ReadPreference.SECONDARY) && Object.keys(this._state.secondaries).length > 0) {
+ // If we have tags, look for servers matching the specific tag
+ if(this.strategyInstance != null) {
+ // Only pick from secondaries
+ var _secondaries = [];
+ for(var key in this._state.secondaries) {
+ _secondaries.push(this._state.secondaries[key]);
+ }
+
+ if(finalReadPreference == ReadPreference.SECONDARY) {
+ // Check out the nearest from only the secondaries
+ connection = this.strategyInstance.checkoutConnection(tags, _secondaries);
+ } else {
+ connection = this.strategyInstance.checkoutConnection(tags, _secondaries);
+ // No candidate servers that match the tags, error
+ if(connection == null || connection instanceof Error) {
+ // No secondary server avilable, attemp to checkout a primary server
+ connection = this.checkoutWriter();
+ // If no connection return an error
+ if(connection == null || connection instanceof Error) {
+ return new Error("No replica set members available for query");
+ }
+ }
+ }
+ } else if(tags != null && typeof tags == 'object') {
+ // Get connection
+ connection = _pickFromTags(this, tags);// = function(self, readPreference, tags) {
+ // No candidate servers that match the tags, error
+ if(connection == null) {
+ return new Error("No replica set members available for query");
+ }
+ } else {
+ connection = _roundRobin(this, tags);
+ }
+ } else if(finalReadPreference == ReadPreference.PRIMARY_PREFERRED) {
+ // Check if there is a primary available and return that if possible
+ connection = this.checkoutWriter();
+ // If no connection available checkout a secondary
+ if(connection == null || connection instanceof Error) {
+ // If we have tags, look for servers matching the specific tag
+ if(tags != null && typeof tags == 'object') {
+ // Get connection
+ connection = _pickFromTags(this, tags);// = function(self, readPreference, tags) {
+ // No candidate servers that match the tags, error
+ if(connection == null) {
+ return new Error("No replica set members available for query");
+ }
+ } else {
+ connection = _roundRobin(this, tags);
+ }
+ }
+ } else if(finalReadPreference == ReadPreference.SECONDARY_PREFERRED) {
+ // If we have tags, look for servers matching the specific tag
+ if(this.strategyInstance != null) {
+ connection = this.strategyInstance.checkoutConnection(tags);
+
+ // No candidate servers that match the tags, error
+ if(connection == null || connection instanceof Error) {
+ // No secondary server avilable, attemp to checkout a primary server
+ connection = this.checkoutWriter();
+ // If no connection return an error
+ if(connection == null || connection instanceof Error) {
+ var preferenceName = finalReadPreference == ReadPreference.SECONDARY ? 'secondary' : finalReadPreference;
+ return new Error("No replica set member available for query with ReadPreference " + preferenceName + " and tags " + JSON.stringify(tags));
+ }
+ }
+ } else if(tags != null && typeof tags == 'object') {
+ // Get connection
+ connection = _pickFromTags(this, tags);// = function(self, readPreference, tags) {
+ // No candidate servers that match the tags, error
+ if(connection == null) {
+ // No secondary server avilable, attemp to checkout a primary server
+ connection = this.checkoutWriter();
+ // If no connection return an error
+ if(connection == null || connection instanceof Error) {
+ var preferenceName = finalReadPreference == ReadPreference.SECONDARY ? 'secondary' : finalReadPreference;
+ return new Error("No replica set member available for query with ReadPreference " + preferenceName + " and tags " + JSON.stringify(tags));
+ }
+ }
+ }
+ } else if(finalReadPreference == ReadPreference.NEAREST && this.strategyInstance != null) {
+ connection = this.strategyInstance.checkoutConnection(tags);
+ } else if(finalReadPreference == ReadPreference.NEAREST && this.strategyInstance == null) {
+ return new Error("A strategy for calculating nearness must be enabled such as ping or statistical");
+ } else if(finalReadPreference == ReadPreference.SECONDARY && Object.keys(this._state.secondaries).length == 0) {
+ if(tags != null && typeof tags == 'object') {
+ var preferenceName = finalReadPreference == ReadPreference.SECONDARY ? 'secondary' : finalReadPreference;
+ return new Error("No replica set member available for query with ReadPreference " + preferenceName + " and tags " + JSON.stringify(tags));
+ } else {
+ return new Error("No replica set secondary available for query with ReadPreference SECONDARY");
+ }
+ } else {
+ connection = this.checkoutWriter();
+ }
+
+ // Return the connection
+ return connection;
+}
+
+/**
+ * @ignore
+ */
+var _pickFromTags = function(self, tags) {
+ // If we have an array or single tag selection
+ var tagObjects = Array.isArray(tags) ? tags : [tags];
+ // Iterate over all tags until we find a candidate server
+ for(var _i = 0; _i < tagObjects.length; _i++) {
+ // Grab a tag object
+ var tagObject = tagObjects[_i];
+ // Matching keys
+ var matchingKeys = Object.keys(tagObject);
+ // Match all the servers that match the provdided tags
+ var keys = Object.keys(self._state.secondaries);
+ var candidateServers = [];
+
+ for(var i = 0; i < keys.length; i++) {
+ var server = self._state.secondaries[keys[i]];
+ // If we have tags match
+ if(server.tags != null) {
+ var matching = true;
+ // Ensure we have all the values
+ for(var j = 0; j < matchingKeys.length; j++) {
+ if(server.tags[matchingKeys[j]] != tagObject[matchingKeys[j]]) {
+ matching = false;
+ break;
+ }
+ }
+
+ // If we have a match add it to the list of matching servers
+ if(matching) {
+ candidateServers.push(server);
+ }
+ }
+ }
+
+ // If we have a candidate server return
+ if(candidateServers.length > 0) {
+ if(self.strategyInstance) return self.strategyInstance.checkoutConnection(tags, candidateServers);
+ // Set instance to return
+ return candidateServers[Math.floor(Math.random() * candidateServers.length)].checkoutReader();
+ }
+ }
+
+ // No connection found
+ return null;
+}
+
+/**
+ * Pick a secondary using round robin
+ *
+ * @ignore
+ */
+function _roundRobin (replset, tags) {
+ var keys = Object.keys(replset._state.secondaries);
+ var key = keys[replset._currentServerChoice++ % keys.length];
+
+ var conn = null != replset._state.secondaries[key]
+ ? replset._state.secondaries[key].checkoutReader()
+ : null;
+
+ // If connection is null fallback to first available secondary
+ if (null == conn) {
+ conn = pickFirstConnectedSecondary(replset, tags);
+ }
+
+ return conn;
+}
+
+/**
+ * @ignore
+ */
+var pickFirstConnectedSecondary = function pickFirstConnectedSecondary(self, tags) {
+ var keys = Object.keys(self._state.secondaries);
+ var connection;
+
+ // Find first available reader if any
+ for(var i = 0; i < keys.length; i++) {
+ connection = self._state.secondaries[keys[i]].checkoutReader();
+ if(connection) return connection;
+ }
+
+ // If we still have a null, read from primary if it's not secondary only
+ if(self._readPreference == ReadPreference.SECONDARY_PREFERRED) {
+ connection = self._state.master.checkoutReader();
+ if(connection) return connection;
+ }
+
+ var preferenceName = self._readPreference == ReadPreference.SECONDARY_PREFERRED
+ ? 'secondary'
+ : self._readPreference;
+
+ return new Error("No replica set member available for query with ReadPreference "
+ + preferenceName + " and tags " + JSON.stringify(tags));
+}
+
+/**
+ * Get list of secondaries
+ * @ignore
+ */
+Object.defineProperty(ReplSet.prototype, "secondaries", {enumerable: true
+ , get: function() {
+ return utils.objectToArray(this._state.secondaries);
+ }
+});
+
+/**
+ * Get list of secondaries
+ * @ignore
+ */
+Object.defineProperty(ReplSet.prototype, "arbiters", {enumerable: true
+ , get: function() {
+ return utils.objectToArray(this._state.arbiters);
+ }
+});
+
diff --git a/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set_state.js b/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set_state.js
new file mode 100644
index 0000000..6f9e143
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/repl_set/repl_set_state.js
@@ -0,0 +1,70 @@
+/**
+ * Interval state object constructor
+ *
+ * @ignore
+ */
+var ReplSetState = function ReplSetState () {
+ this.errorMessages = [];
+ this.secondaries = {};
+ this.addresses = {};
+ this.arbiters = {};
+ this.passives = {};
+ this.members = [];
+ this.errors = {};
+ this.setName = null;
+ this.master = null;
+}
+
+ReplSetState.prototype.hasValidServers = function() {
+ var validServers = [];
+ if(this.master && this.master.isConnected()) return true;
+
+ if(this.secondaries) {
+ var keys = Object.keys(this.secondaries)
+ for(var i = 0; i < keys.length; i++) {
+ if(this.secondaries[keys[i]].isConnected())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+ReplSetState.prototype.getAllReadServers = function() {
+ var candidate_servers = [];
+ for(var name in this.addresses) {
+ candidate_servers.push(this.addresses[name]);
+ }
+
+ // Return all possible read candidates
+ return candidate_servers;
+}
+
+ReplSetState.prototype.addServer = function(server, master) {
+ server.name = master.me;
+
+ if(master.ismaster) {
+ this.master = server;
+ this.addresses[server.name] = server;
+ } else if(master.secondary) {
+ this.secondaries[server.name] = server;
+ this.addresses[server.name] = server;
+ } else if(master.arbiters) {
+ this.arbiters[server.name] = server;
+ this.addresses[server.name] = server;
+ }
+}
+
+ReplSetState.prototype.contains = function(host) {
+ return this.addresses[host] != null;
+}
+
+ReplSetState.prototype.isPrimary = function(server) {
+ return this.master && this.master.name == server.name;
+}
+
+ReplSetState.prototype.isSecondary = function(server) {
+ return this.secondaries[server.name] != null;
+}
+
+exports.ReplSetState = ReplSetState;
diff --git a/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/ping_strategy.js b/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/ping_strategy.js
new file mode 100644
index 0000000..e5a7367
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/ping_strategy.js
@@ -0,0 +1,304 @@
+var Server = require("../../server").Server
+ , format = require('util').format;
+
+// The ping strategy uses pings each server and records the
+// elapsed time for the server so it can pick a server based on lowest
+// return time for the db command {ping:true}
+var PingStrategy = exports.PingStrategy = function(replicaset, secondaryAcceptableLatencyMS) {
+ this.replicaset = replicaset;
+ this.secondaryAcceptableLatencyMS = secondaryAcceptableLatencyMS;
+ this.state = 'disconnected';
+ this.pingInterval = 5000;
+ // Class instance
+ this.Db = require("../../../db").Db;
+ // Active db connections
+ this.dbs = {};
+ // Current server index
+ this.index = 0;
+ // Logger api
+ this.Logger = null;
+}
+
+// Starts any needed code
+PingStrategy.prototype.start = function(callback) {
+ // already running?
+ if ('connected' == this.state) return;
+
+ this.state = 'connected';
+
+ // Start ping server
+ this._pingServer(callback);
+}
+
+// Stops and kills any processes running
+PingStrategy.prototype.stop = function(callback) {
+ // Stop the ping process
+ this.state = 'disconnected';
+
+ // Stop all the server instances
+ for(var key in this.dbs) {
+ this.dbs[key].close();
+ }
+
+ // optional callback
+ callback && callback(null, null);
+}
+
+PingStrategy.prototype.checkoutConnection = function(tags, secondaryCandidates) {
+ // Servers are picked based on the lowest ping time and then servers that lower than that + secondaryAcceptableLatencyMS
+ // Create a list of candidat servers, containing the primary if available
+ var candidateServers = [];
+ var self = this;
+
+ // If we have not provided a list of candidate servers use the default setup
+ if(!Array.isArray(secondaryCandidates)) {
+ candidateServers = this.replicaset._state.master != null ? [this.replicaset._state.master] : [];
+ // Add all the secondaries
+ var keys = Object.keys(this.replicaset._state.secondaries);
+ for(var i = 0; i < keys.length; i++) {
+ candidateServers.push(this.replicaset._state.secondaries[keys[i]])
+ }
+ } else {
+ candidateServers = secondaryCandidates;
+ }
+
+ // Final list of eligable server
+ var finalCandidates = [];
+
+ // If we have tags filter by tags
+ if(tags != null && typeof tags == 'object') {
+ // If we have an array or single tag selection
+ var tagObjects = Array.isArray(tags) ? tags : [tags];
+ // Iterate over all tags until we find a candidate server
+ for(var _i = 0; _i < tagObjects.length; _i++) {
+ // Grab a tag object
+ var tagObject = tagObjects[_i];
+ // Matching keys
+ var matchingKeys = Object.keys(tagObject);
+ // Remove any that are not tagged correctly
+ for(var i = 0; i < candidateServers.length; i++) {
+ var server = candidateServers[i];
+ // If we have tags match
+ if(server.tags != null) {
+ var matching = true;
+
+ // Ensure we have all the values
+ for(var j = 0; j < matchingKeys.length; j++) {
+ if(server.tags[matchingKeys[j]] != tagObject[matchingKeys[j]]) {
+ matching = false;
+ break;
+ }
+ }
+
+ // If we have a match add it to the list of matching servers
+ if(matching) {
+ finalCandidates.push(server);
+ }
+ }
+ }
+ }
+ } else {
+ // Final array candidates
+ var finalCandidates = candidateServers;
+ }
+
+ // Sort by ping time
+ finalCandidates.sort(function(a, b) {
+ return a.runtimeStats['pingMs'] > b.runtimeStats['pingMs'];
+ });
+
+ if(0 === finalCandidates.length)
+ return new Error("No replica set members available for query");
+
+ // find lowest server with a ping time
+ var lowest = finalCandidates.filter(function (server) {
+ return undefined != server.runtimeStats.pingMs;
+ })[0];
+
+ if(!lowest) {
+ lowest = finalCandidates[0];
+ }
+
+ // convert to integer
+ var lowestPing = lowest.runtimeStats.pingMs | 0;
+
+ // determine acceptable latency
+ var acceptable = lowestPing + this.secondaryAcceptableLatencyMS;
+
+ // remove any server responding slower than acceptable
+ var len = finalCandidates.length;
+ while(len--) {
+ if(finalCandidates[len].runtimeStats['pingMs'] > acceptable) {
+ finalCandidates.splice(len, 1);
+ }
+ }
+
+ if(self.logger && self.logger.debug) {
+ self.logger.debug("Ping strategy selection order for tags", tags);
+ finalCandidates.forEach(function(c) {
+ self.logger.debug(format("%s:%s = %s ms", c.host, c.port, c.runtimeStats['pingMs']), null);
+ })
+ }
+
+ // If no candidates available return an error
+ if(finalCandidates.length == 0)
+ return new Error("No replica set members available for query");
+
+ // Ensure no we don't overflow
+ this.index = this.index % finalCandidates.length
+ // Pick a random acceptable server
+ var connection = finalCandidates[this.index].checkoutReader();
+ // Point to next candidate (round robin style)
+ this.index = this.index + 1;
+
+ if(self.logger && self.logger.debug) {
+ if(connection)
+ self.logger.debug("picked server %s:%s", connection.socketOptions.host, connection.socketOptions.port);
+ }
+
+ return connection;
+}
+
+PingStrategy.prototype._pingServer = function(callback) {
+ var self = this;
+
+ // Ping server function
+ var pingFunction = function() {
+ // Our state changed to disconnected or destroyed return
+ if(self.state == 'disconnected' || self.state == 'destroyed') return;
+ // If the replicaset is destroyed return
+ if(self.replicaset.isDestroyed() || self.replicaset._serverState == 'disconnected') return
+
+ // Create a list of all servers we can send the ismaster command to
+ var allServers = self.replicaset._state.master != null ? [self.replicaset._state.master] : [];
+
+ // Secondary keys
+ var keys = Object.keys(self.replicaset._state.secondaries);
+ // Add all secondaries
+ for(var i = 0; i < keys.length; i++) {
+ allServers.push(self.replicaset._state.secondaries[keys[i]]);
+ }
+
+ // Number of server entries
+ var numberOfEntries = allServers.length;
+
+ // We got keys
+ for(var i = 0; i < allServers.length; i++) {
+
+ // We got a server instance
+ var server = allServers[i];
+
+ // Create a new server object, avoid using internal connections as they might
+ // be in an illegal state
+ new function(serverInstance) {
+ var _db = self.dbs[serverInstance.host + ":" + serverInstance.port];
+ // If we have a db
+ if(_db != null) {
+ // Startup time of the command
+ var startTime = Date.now();
+
+ // Execute ping command in own scope
+ var _ping = function(__db, __serverInstance) {
+ // Execute ping on this connection
+ __db.executeDbCommand({ping:1}, {failFast:true}, function(err) {
+ if(err) {
+ delete self.dbs[__db.serverConfig.host + ":" + __db.serverConfig.port];
+ __db.close();
+ return done();
+ }
+
+ if(null != __serverInstance.runtimeStats && __serverInstance.isConnected()) {
+ __serverInstance.runtimeStats['pingMs'] = Date.now() - startTime;
+ }
+
+ done();
+ });
+ };
+ // Ping
+ _ping(_db, serverInstance);
+ } else {
+ var connectTimeoutMS = self.replicaset.options.socketOptions
+ ? self.replicaset.options.socketOptions.connectTimeoutMS : 0
+
+ // Create a new master connection
+ var _server = new Server(serverInstance.host, serverInstance.port, {
+ auto_reconnect: false,
+ returnIsMasterResults: true,
+ slaveOk: true,
+ poolSize: 1,
+ socketOptions: { connectTimeoutMS: connectTimeoutMS },
+ ssl: self.replicaset.ssl,
+ sslValidate: self.replicaset.sslValidate,
+ sslCA: self.replicaset.sslCA,
+ sslCert: self.replicaset.sslCert,
+ sslKey: self.replicaset.sslKey,
+ sslPass: self.replicaset.sslPass
+ });
+
+ // Create Db instance
+ var _db = new self.Db('local', _server, { safe: true });
+ _db.on("close", function() {
+ delete self.dbs[this.serverConfig.host + ":" + this.serverConfig.port];
+ })
+
+ var _ping = function(__db, __serverInstance) {
+ if(self.state == 'disconnected') {
+ self.stop();
+ return;
+ }
+
+ __db.open(function(err, db) {
+ if(self.state == 'disconnected' && __db != null) {
+ return __db.close();
+ }
+
+ if(err) {
+ delete self.dbs[__db.serverConfig.host + ":" + __db.serverConfig.port];
+ __db.close();
+ return done();
+ }
+
+ // Save instance
+ self.dbs[__db.serverConfig.host + ":" + __db.serverConfig.port] = __db;
+
+ // Startup time of the command
+ var startTime = Date.now();
+
+ // Execute ping on this connection
+ __db.executeDbCommand({ping:1}, {failFast:true}, function(err) {
+ if(err) {
+ delete self.dbs[__db.serverConfig.host + ":" + __db.serverConfig.port];
+ __db.close();
+ return done();
+ }
+
+ if(null != __serverInstance.runtimeStats && __serverInstance.isConnected()) {
+ __serverInstance.runtimeStats['pingMs'] = Date.now() - startTime;
+ }
+
+ done();
+ });
+ });
+ };
+
+ _ping(_db, serverInstance);
+ }
+
+ function done() {
+ // Adjust the number of checks
+ numberOfEntries--;
+
+ // If we are done with all results coming back trigger ping again
+ if(0 === numberOfEntries && 'connected' == self.state) {
+ setTimeout(pingFunction, self.pingInterval);
+ }
+ }
+ }(server);
+ }
+ }
+
+ // Start pingFunction
+ pingFunction();
+
+ callback && callback(null);
+}
diff --git a/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/statistics_strategy.js b/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/statistics_strategy.js
new file mode 100644
index 0000000..f9b8c46
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/statistics_strategy.js
@@ -0,0 +1,80 @@
+// The Statistics strategy uses the measure of each end-start time for each
+// query executed against the db to calculate the mean, variance and standard deviation
+// and pick the server which the lowest mean and deviation
+var StatisticsStrategy = exports.StatisticsStrategy = function(replicaset) {
+ this.replicaset = replicaset;
+ // Logger api
+ this.Logger = null;
+}
+
+// Starts any needed code
+StatisticsStrategy.prototype.start = function(callback) {
+ callback && callback(null, null);
+}
+
+StatisticsStrategy.prototype.stop = function(callback) {
+ callback && callback(null, null);
+}
+
+StatisticsStrategy.prototype.checkoutConnection = function(tags, secondaryCandidates) {
+ // Servers are picked based on the lowest ping time and then servers that lower than that + secondaryAcceptableLatencyMS
+ // Create a list of candidat servers, containing the primary if available
+ var candidateServers = [];
+
+ // If we have not provided a list of candidate servers use the default setup
+ if(!Array.isArray(secondaryCandidates)) {
+ candidateServers = this.replicaset._state.master != null ? [this.replicaset._state.master] : [];
+ // Add all the secondaries
+ var keys = Object.keys(this.replicaset._state.secondaries);
+ for(var i = 0; i < keys.length; i++) {
+ candidateServers.push(this.replicaset._state.secondaries[keys[i]])
+ }
+ } else {
+ candidateServers = secondaryCandidates;
+ }
+
+ // Final list of eligable server
+ var finalCandidates = [];
+
+ // If we have tags filter by tags
+ if(tags != null && typeof tags == 'object') {
+ // If we have an array or single tag selection
+ var tagObjects = Array.isArray(tags) ? tags : [tags];
+ // Iterate over all tags until we find a candidate server
+ for(var _i = 0; _i < tagObjects.length; _i++) {
+ // Grab a tag object
+ var tagObject = tagObjects[_i];
+ // Matching keys
+ var matchingKeys = Object.keys(tagObject);
+ // Remove any that are not tagged correctly
+ for(var i = 0; i < candidateServers.length; i++) {
+ var server = candidateServers[i];
+ // If we have tags match
+ if(server.tags != null) {
+ var matching = true;
+
+ // Ensure we have all the values
+ for(var j = 0; j < matchingKeys.length; j++) {
+ if(server.tags[matchingKeys[j]] != tagObject[matchingKeys[j]]) {
+ matching = false;
+ break;
+ }
+ }
+
+ // If we have a match add it to the list of matching servers
+ if(matching) {
+ finalCandidates.push(server);
+ }
+ }
+ }
+ }
+ } else {
+ // Final array candidates
+ var finalCandidates = candidateServers;
+ }
+
+ // If no candidates available return an error
+ if(finalCandidates.length == 0) return new Error("No replica set members available for query");
+ // Pick a random server
+ return finalCandidates[Math.round(Math.random(1000000) * (finalCandidates.length - 1))].checkoutReader();
+}
diff --git a/node_modules/mongodb/lib/mongodb/connection/server.js b/node_modules/mongodb/lib/mongodb/connection/server.js
new file mode 100644
index 0000000..7b5df1e
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/server.js
@@ -0,0 +1,986 @@
+var Connection = require('./connection').Connection,
+ ReadPreference = require('./read_preference').ReadPreference,
+ DbCommand = require('../commands/db_command').DbCommand,
+ MongoReply = require('../responses/mongo_reply').MongoReply,
+ ConnectionPool = require('./connection_pool').ConnectionPool,
+ EventEmitter = require('events').EventEmitter,
+ Base = require('./base').Base,
+ utils = require('../utils'),
+ timers = require('timers'),
+ inherits = require('util').inherits;
+
+// Set processor, setImmediate if 0.10 otherwise nextTick
+var processor = timers.setImmediate ? timers.setImmediate : process.nextTick;
+
+/**
+ * Class representing a single MongoDB Server connection
+ *
+ * Options
+ * - **readPreference** {String, default:null}, set's the read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
+ * - **ssl** {Boolean, default:false}, use ssl connection (needs to have a mongod server with ssl support)
+ * - **sslValidate** {Boolean, default:false}, validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher)
+ * - **sslCA** {Array, default:null}, Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
+ * - **sslCert** {Buffer/String, default:null}, String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
+ * - **sslKey** {Buffer/String, default:null}, String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
+ * - **sslPass** {Buffer/String, default:null}, String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher)
+ * - **poolSize** {Number, default:5}, number of connections in the connection pool, set to 5 as default for legacy reasons.
+ * - **socketOptions** {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number))
+ * - **logger** {Object, default:null}, an object representing a logger that you want to use, needs to support functions debug, log, error **({error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}})**.
+ * - **auto_reconnect** {Boolean, default:false}, reconnect on error.
+ * - **disableDriverBSONSizeCheck** {Boolean, default:false}, force the server to error if the BSON message is to big
+ *
+ * @class Represents a Server connection.
+ * @param {String} host the server host
+ * @param {Number} port the server port
+ * @param {Object} [options] optional options for insert command
+ */
+function Server(host, port, options) {
+ // Set up Server instance
+ if(!(this instanceof Server)) return new Server(host, port, options);
+
+ // Set up event emitter
+ Base.call(this);
+
+ // Ensure correct values
+ if(port != null && typeof port == 'object') {
+ options = port;
+ port = Connection.DEFAULT_PORT;
+ }
+
+ var self = this;
+ this.host = host;
+ this.port = port;
+ this.options = options == null ? {} : options;
+ this.internalConnection;
+ this.internalMaster = false;
+ this.connected = false;
+ this.poolSize = this.options.poolSize == null ? 5 : this.options.poolSize;
+ this.disableDriverBSONSizeCheck = this.options.disableDriverBSONSizeCheck != null ? this.options.disableDriverBSONSizeCheck : false;
+ this._used = false;
+ this.replicasetInstance = null;
+
+ // Emit open setup
+ this.emitOpen = this.options.emitOpen || true;
+ // Set ssl as connection method
+ this.ssl = this.options.ssl == null ? false : this.options.ssl;
+ // Set ssl validation
+ this.sslValidate = this.options.sslValidate == null ? false : this.options.sslValidate;
+ // Set the ssl certificate authority (array of Buffer/String keys)
+ this.sslCA = Array.isArray(this.options.sslCA) ? this.options.sslCA : null;
+ // Certificate to present to the server
+ this.sslCert = this.options.sslCert;
+ // Certificate private key if in separate file
+ this.sslKey = this.options.sslKey;
+ // Password to unlock private key
+ this.sslPass = this.options.sslPass;
+
+ // Ensure we are not trying to validate with no list of certificates
+ if(this.sslValidate && (!Array.isArray(this.sslCA) || this.sslCA.length == 0)) {
+ throw new Error("The driver expects an Array of CA certificates in the sslCA parameter when enabling sslValidate");
+ }
+
+ // Get the readPreference
+ var readPreference = this.options['readPreference'];
+ // If readPreference is an object get the mode string
+ var validateReadPreference = readPreference != null && typeof readPreference == 'object' ? readPreference.mode : readPreference;
+ // Read preference setting
+ if(validateReadPreference != null) {
+ if(validateReadPreference != ReadPreference.PRIMARY && validateReadPreference != ReadPreference.SECONDARY && validateReadPreference != ReadPreference.NEAREST
+ && validateReadPreference != ReadPreference.SECONDARY_PREFERRED && validateReadPreference != ReadPreference.PRIMARY_PREFERRED) {
+ throw new Error("Illegal readPreference mode specified, " + validateReadPreference);
+ }
+
+ // Set read Preference
+ this._readPreference = readPreference;
+ } else {
+ this._readPreference = null;
+ }
+
+ // Contains the isMaster information returned from the server
+ this.isMasterDoc;
+
+ // Set default connection pool options
+ this.socketOptions = this.options.socketOptions != null ? this.options.socketOptions : {};
+ if(this.disableDriverBSONSizeCheck) this.socketOptions.disableDriverBSONSizeCheck = this.disableDriverBSONSizeCheck;
+
+ // Set ssl up if it's defined
+ if(this.ssl) {
+ this.socketOptions.ssl = true;
+ // Set ssl validation
+ this.socketOptions.sslValidate = this.sslValidate == null ? false : this.sslValidate;
+ // Set the ssl certificate authority (array of Buffer/String keys)
+ this.socketOptions.sslCA = Array.isArray(this.sslCA) ? this.sslCA : null;
+ // Set certificate to present
+ this.socketOptions.sslCert = this.sslCert;
+ // Set certificate to present
+ this.socketOptions.sslKey = this.sslKey;
+ // Password to unlock private key
+ this.socketOptions.sslPass = this.sslPass;
+ }
+
+ // Set up logger if any set
+ this.logger = this.options.logger != null
+ && (typeof this.options.logger.debug == 'function')
+ && (typeof this.options.logger.error == 'function')
+ && (typeof this.options.logger.log == 'function')
+ ? this.options.logger : {error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}};
+
+ // Just keeps list of events we allow
+ this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[], timeout:[]};
+ // Internal state of server connection
+ this._serverState = 'disconnected';
+ // Contains state information about server connection
+ this._state = {'runtimeStats': {'queryStats':new RunningStats()}};
+ // Do we record server stats or not
+ this.recordQueryStats = false;
+};
+
+/**
+ * @ignore
+ */
+inherits(Server, Base);
+
+//
+// Deprecated, USE ReadPreferences class
+//
+Server.READ_PRIMARY = ReadPreference.PRIMARY;
+Server.READ_SECONDARY = ReadPreference.SECONDARY_PREFERRED;
+Server.READ_SECONDARY_ONLY = ReadPreference.SECONDARY;
+
+/**
+ * Always ourselves
+ * @ignore
+ */
+Server.prototype.setReadPreference = function(readPreference) {
+ this._readPreference = readPreference;
+}
+
+/**
+ * @ignore
+ */
+Server.prototype.isMongos = function() {
+ return this.isMasterDoc != null && this.isMasterDoc['msg'] == "isdbgrid" ? true : false;
+}
+
+/**
+ * @ignore
+ */
+Server.prototype._isUsed = function() {
+ return this._used;
+}
+
+/**
+ * @ignore
+ */
+Server.prototype.close = function(callback) {
+ // Set server status as disconnected
+ this._serverState = 'destroyed';
+ // Remove all local listeners
+ this.removeAllListeners();
+
+ if(this.connectionPool != null) {
+ // Remove all the listeners on the pool so it does not fire messages all over the place
+ this.connectionPool.removeAllEventListeners();
+ // Close the connection if it's open
+ this.connectionPool.stop(true);
+ }
+
+ // Emit close event
+ if(this.db && !this.isSetMember()) {
+ var self = this;
+ processor(function() {
+ self._emitAcrossAllDbInstances(self, null, "close", null, null, true)
+ })
+ }
+
+ // Peform callback if present
+ if(typeof callback === 'function') callback(null);
+};
+
+Server.prototype.isDestroyed = function() {
+ return this._serverState == 'destroyed';
+}
+
+/**
+ * @ignore
+ */
+Server.prototype.isConnected = function() {
+ return this.connectionPool.isConnected();
+}
+
+/**
+ * @ignore
+ */
+Server.prototype.canWrite = Server.prototype.isConnected;
+Server.prototype.canRead = Server.prototype.isConnected;
+
+Server.prototype.isAutoReconnect = function() {
+ if(this.isSetMember()) return false;
+ return this.options.auto_reconnect != null ? this.options.auto_reconnect : true;
+}
+
+/**
+ * @ignore
+ */
+Server.prototype.allServerInstances = function() {
+ return [this];
+}
+
+/**
+ * @ignore
+ */
+Server.prototype.isSetMember = function() {
+ return this.replicasetInstance != null || this.mongosInstance != null;
+}
+
+/**
+ * Assigns a replica set to this `server`.
+ *
+ * @param {ReplSet} replset
+ * @ignore
+ */
+Server.prototype.assignReplicaSet = function (replset) {
+ this.replicasetInstance = replset;
+ this.inheritReplSetOptionsFrom(replset);
+ this.enableRecordQueryStats(replset.recordQueryStats);
+}
+
+/**
+ * Takes needed options from `replset` and overwrites
+ * our own options.
+ *
+ * @param {ReplSet} replset
+ * @ignore
+ */
+Server.prototype.inheritReplSetOptionsFrom = function (replset) {
+ this.socketOptions = {};
+ this.socketOptions.connectTimeoutMS = replset.options.socketOptions.connectTimeoutMS || 30000;
+
+ if(replset.options.ssl) {
+ // Set ssl on
+ this.socketOptions.ssl = true;
+ // Set ssl validation
+ this.socketOptions.sslValidate = replset.options.sslValidate == null ? false : replset.options.sslValidate;
+ // Set the ssl certificate authority (array of Buffer/String keys)
+ this.socketOptions.sslCA = Array.isArray(replset.options.sslCA) ? replset.options.sslCA : null;
+ // Set certificate to present
+ this.socketOptions.sslCert = replset.options.sslCert;
+ // Set certificate to present
+ this.socketOptions.sslKey = replset.options.sslKey;
+ // Password to unlock private key
+ this.socketOptions.sslPass = replset.options.sslPass;
+ }
+
+ // If a socket option object exists clone it
+ if(utils.isObject(replset.options.socketOptions)) {
+ var keys = Object.keys(replset.options.socketOptions);
+ for(var i = 0; i < keys.length; i++)
+ this.socketOptions[keys[i]] = replset.options.socketOptions[keys[i]];
+ }
+}
+
+/**
+ * Opens this server connection.
+ *
+ * @ignore
+ */
+Server.prototype.connect = function(dbInstance, options, callback) {
+ if('function' === typeof options) callback = options, options = {};
+ if(options == null) options = {};
+ if(!('function' === typeof callback)) callback = null;
+ var self = this;
+ // Save the options
+ this.options = options;
+
+ // Currently needed to work around problems with multiple connections in a pool with ssl
+ // TODO fix if possible
+ if(this.ssl == true) {
+ // Set up socket options for ssl
+ this.socketOptions.ssl = true;
+ // Set ssl validation
+ this.socketOptions.sslValidate = this.sslValidate == null ? false : this.sslValidate;
+ // Set the ssl certificate authority (array of Buffer/String keys)
+ this.socketOptions.sslCA = Array.isArray(this.sslCA) ? this.sslCA : null;
+ // Set certificate to present
+ this.socketOptions.sslCert = this.sslCert;
+ // Set certificate to present
+ this.socketOptions.sslKey = this.sslKey;
+ // Password to unlock private key
+ this.socketOptions.sslPass = this.sslPass;
+ }
+
+ // Let's connect
+ var server = this;
+ // Let's us override the main receiver of events
+ var eventReceiver = options.eventReceiver != null ? options.eventReceiver : this;
+ // Save reference to dbInstance
+ this.db = dbInstance; // `db` property matches ReplSet and Mongos
+ this.dbInstances = [dbInstance];
+
+ // Force connection pool if there is one
+ if(server.connectionPool) server.connectionPool.stop();
+ // Set server state to connecting
+ this._serverState = 'connecting';
+
+ if(server.connectionPool != null) {
+ // Remove all the listeners on the pool so it does not fire messages all over the place
+ this.connectionPool.removeAllEventListeners();
+ // Close the connection if it's open
+ this.connectionPool.stop(true);
+ }
+
+ this.connectionPool = new ConnectionPool(this.host, this.port, this.poolSize, dbInstance.bson, this.socketOptions);
+ var connectionPool = this.connectionPool;
+ // If ssl is not enabled don't wait between the pool connections
+ if(this.ssl == null || !this.ssl) connectionPool._timeToWait = null;
+ // Set logger on pool
+ connectionPool.logger = this.logger;
+ connectionPool.bson = dbInstance.bson;
+
+ // Set basic parameters passed in
+ var returnIsMasterResults = options.returnIsMasterResults == null ? false : options.returnIsMasterResults;
+
+ // Create a default connect handler, overriden when using replicasets
+ var connectCallback = function(_server) {
+ return function(err, reply) {
+ // ensure no callbacks get called twice
+ var internalCallback = callback;
+ callback = null;
+ // Assign the server
+ _server = _server != null ? _server : server;
+
+ // If something close down the connection and removed the callback before
+ // proxy killed connection etc, ignore the erorr as close event was isssued
+ if(err != null && internalCallback == null) return;
+ // Internal callback
+ if(err != null) return internalCallback(err, null, _server);
+ _server.master = reply.documents[0].ismaster == 1 ? true : false;
+ _server.connectionPool.setMaxBsonSize(reply.documents[0].maxBsonObjectSize);
+ _server.connectionPool.setMaxMessageSizeBytes(reply.documents[0].maxMessageSizeBytes);
+ // Set server state to connEcted
+ _server._serverState = 'connected';
+ // Set server as connected
+ _server.connected = true;
+ // Save document returned so we can query it
+ _server.isMasterDoc = reply.documents[0];
+
+ if(self.emitOpen)
+ _server._emitAcrossAllDbInstances(_server, eventReceiver, "open", null, returnIsMasterResults ? reply : dbInstance, null);
+
+ // If we have it set to returnIsMasterResults
+ if(returnIsMasterResults) {
+ internalCallback(null, reply, _server);
+ } else {
+ internalCallback(null, dbInstance, _server);
+ }
+ }
+ };
+
+ // Let's us override the main connect callback
+ var connectHandler = options.connectHandler == null ? connectCallback(server) : options.connectHandler;
+
+ // Set up on connect method
+ connectionPool.on("poolReady", function() {
+ // Create db command and Add the callback to the list of callbacks by the request id (mapping outgoing messages to correct callbacks)
+ var db_command = DbCommand.NcreateIsMasterCommand(dbInstance, dbInstance.databaseName);
+ // Check out a reader from the pool
+ var connection = connectionPool.checkoutConnection();
+ // Register handler for messages
+ server._registerHandler(db_command, false, connection, connectHandler);
+ // Write the command out
+ connection.write(db_command);
+ })
+
+ // Set up item connection
+ connectionPool.on("message", function(message) {
+ // Attempt to parse the message
+ try {
+ // Create a new mongo reply
+ var mongoReply = new MongoReply()
+ // Parse the header
+ mongoReply.parseHeader(message, connectionPool.bson)
+
+ // If message size is not the same as the buffer size
+ // something went terribly wrong somewhere
+ if(mongoReply.messageLength != message.length) {
+ // Emit the error
+ if(eventReceiver.listeners("error") && eventReceiver.listeners("error").length > 0) eventReceiver.emit("error", new Error("bson length is different from message length"), server);
+ // Remove all listeners
+ server.removeAllListeners();
+ } else {
+ var startDate = new Date().getTime();
+
+ // Callback instance
+ var callbackInfo = server._findHandler(mongoReply.responseTo.toString());
+
+ // The command executed another request, log the handler again under that request id
+ if(mongoReply.requestId > 0 && mongoReply.cursorId.toString() != "0"
+ && callbackInfo && callbackInfo.info && callbackInfo.info.exhaust) {
+ server._reRegisterHandler(mongoReply.requestId, callbackInfo);
+ }
+
+ // Only execute callback if we have a caller
+ // chained is for findAndModify as it does not respect write concerns
+ if(callbackInfo && callbackInfo.callback && callbackInfo.info && Array.isArray(callbackInfo.info.chained)) {
+ // Check if callback has already been fired (missing chain command)
+ var chained = callbackInfo.info.chained;
+ var numberOfFoundCallbacks = 0;
+ for(var i = 0; i < chained.length; i++) {
+ if(server._hasHandler(chained[i])) numberOfFoundCallbacks++;
+ }
+
+ // If we have already fired then clean up rest of chain and move on
+ if(numberOfFoundCallbacks != chained.length) {
+ for(var i = 0; i < chained.length; i++) {
+ server._removeHandler(chained[i]);
+ }
+
+ // Just return from function
+ return;
+ }
+
+ // Parse the body
+ mongoReply.parseBody(message, connectionPool.bson, callbackInfo.info.raw, function(err) {
+ if(err != null) {
+ // If pool connection is already closed
+ if(server._serverState === 'disconnected') return;
+ // Set server state to disconnected
+ server._serverState = 'disconnected';
+ // Remove all listeners and close the connection pool
+ server.removeAllListeners();
+ connectionPool.stop(true);
+
+ // If we have a callback return the error
+ if(typeof callback === 'function') {
+ // ensure no callbacks get called twice
+ var internalCallback = callback;
+ callback = null;
+ // Perform callback
+ internalCallback(new Error("connection closed due to parseError"), null, server);
+ } else if(server.isSetMember()) {
+ if(server.listeners("parseError") && server.listeners("parseError").length > 0) server.emit("parseError", new Error("connection closed due to parseError"), server);
+ } else {
+ if(eventReceiver.listeners("parseError") && eventReceiver.listeners("parseError").length > 0) eventReceiver.emit("parseError", new Error("connection closed due to parseError"), server);
+ }
+
+ // If we are a single server connection fire errors correctly
+ if(!server.isSetMember()) {
+ // Fire all callback errors
+ server.__executeAllCallbacksWithError(new Error("connection closed due to parseError"));
+ // Emit error
+ server._emitAcrossAllDbInstances(server, eventReceiver, "parseError", server, null, true);
+ }
+ // Short cut
+ return;
+ }
+
+ // Fetch the callback
+ var callbackInfo = server._findHandler(mongoReply.responseTo.toString());
+ // If we have an error let's execute the callback and clean up all other
+ // chained commands
+ var firstResult = mongoReply && mongoReply.documents;
+
+ // Check for an error, if we have one let's trigger the callback and clean up
+ // The chained callbacks
+ if(firstResult[0].err != null || firstResult[0].errmsg != null) {
+ // Cleanup the remaining callback
+ if(Array.isArray(callbackInfo.info.chained)) {
+ for(var i = 0; i < callbackInfo.info.chained.length; i++) {
+ if(callbackInfo.info.chained[i] != mongoReply.responseTo)
+ server._removeHandler(callbackInfo.info.chained[i]);
+ }
+ }
+ // Trigger the callback for the error
+ server._callHandler(mongoReply.responseTo, mongoReply, null);
+ } else {
+ var chainedIds = callbackInfo.info.chained;
+
+ if(chainedIds.length > 0 && chainedIds[chainedIds.length - 1] == mongoReply.responseTo) {
+ // Cleanup all other chained calls
+ chainedIds.pop();
+ // Remove listeners
+ for(var i = 0; i < chainedIds.length; i++) server._removeHandler(chainedIds[i]);
+ // Call the handler
+ server._callHandler(mongoReply.responseTo, callbackInfo.info.results.shift(), null);
+ } else{
+ // Add the results to all the results
+ for(var i = 0; i < chainedIds.length; i++) {
+ var handler = server._findHandler(chainedIds[i]);
+ // Check if we have an object, if it's the case take the current object commands and
+ // and add this one
+ if(handler.info != null) {
+ handler.info.results = Array.isArray(callbackInfo.info.results) ? callbackInfo.info.results : [];
+ handler.info.results.push(mongoReply);
+ }
+ }
+ }
+ }
+ });
+ } else if(callbackInfo && callbackInfo.callback && callbackInfo.info) {
+ // Parse the body
+ mongoReply.parseBody(message, connectionPool.bson, callbackInfo.info.raw, function(err) {
+ if(err != null) {
+ // If pool connection is already closed
+ if(server._serverState === 'disconnected') return;
+ // Set server state to disconnected
+ server._serverState = 'disconnected';
+ // Remove all listeners and close the connection pool
+ server.removeAllListeners();
+ connectionPool.stop(true);
+
+ // If we have a callback return the error
+ if(typeof callback === 'function') {
+ // ensure no callbacks get called twice
+ var internalCallback = callback;
+ callback = null;
+ // Perform callback
+ internalCallback(new Error("connection closed due to parseError"), null, server);
+ } else if(server.isSetMember()) {
+ if(server.listeners("parseError") && server.listeners("parseError").length > 0) server.emit("parseError", new Error("connection closed due to parseError"), server);
+ } else {
+ if(eventReceiver.listeners("parseError") && eventReceiver.listeners("parseError").length > 0) eventReceiver.emit("parseError", new Error("connection closed due to parseError"), server);
+ }
+
+ // If we are a single server connection fire errors correctly
+ if(!server.isSetMember()) {
+ // Fire all callback errors
+ server.__executeAllCallbacksWithError(new Error("connection closed due to parseError"));
+ // Emit error
+ server._emitAcrossAllDbInstances(server, eventReceiver, "parseError", server, null, true);
+ }
+ // Short cut
+ return;
+ }
+
+ // Let's record the stats info if it's enabled
+ if(server.recordQueryStats == true && server._state['runtimeStats'] != null
+ && server._state.runtimeStats['queryStats'] instanceof RunningStats) {
+ console.log("============================= log stats")
+ // Add data point to the running statistics object
+ server._state.runtimeStats.queryStats.push(new Date().getTime() - callbackInfo.info.start);
+ }
+
+ server._callHandler(mongoReply.responseTo, mongoReply, null);
+ });
+ }
+ }
+ } catch (err) {
+ // Throw error in next tick
+ processor(function() {
+ throw err;
+ })
+ }
+ });
+
+ // Handle timeout
+ connectionPool.on("timeout", function(err) {
+ // If pool connection is already closed
+ if(server._serverState === 'disconnected'
+ || server._serverState === 'destroyed') return;
+ // Set server state to disconnected
+ server._serverState = 'disconnected';
+ // If we have a callback return the error
+ if(typeof callback === 'function') {
+ // ensure no callbacks get called twice
+ var internalCallback = callback;
+ callback = null;
+ // Perform callback
+ internalCallback(err, null, server);
+ } else if(server.isSetMember()) {
+ if(server.listeners("timeout") && server.listeners("timeout").length > 0) server.emit("timeout", err, server);
+ } else {
+ if(eventReceiver.listeners("timeout") && eventReceiver.listeners("timeout").length > 0) eventReceiver.emit("timeout", err, server);
+ }
+
+ // If we are a single server connection fire errors correctly
+ if(!server.isSetMember()) {
+ // Fire all callback errors
+ server.__executeAllCallbacksWithError(err);
+ // Emit error
+ server._emitAcrossAllDbInstances(server, eventReceiver, "timeout", err, server, true);
+ }
+ });
+
+ // Handle errors
+ connectionPool.on("error", function(message, connection, error_options) {
+ // If pool connection is already closed
+ if(server._serverState === 'disconnected'
+ || server._serverState === 'destroyed') return;
+ // Set server state to disconnected
+ server._serverState = 'disconnected';
+ // Error message
+ var error_message = new Error(message && message.err ? message.err : message);
+ // Error message coming from ssl
+ if(error_options && error_options.ssl) error_message.ssl = true;
+ // If we have a callback return the error
+ if(typeof callback === 'function') {
+ // ensure no callbacks get called twice
+ var internalCallback = callback;
+ callback = null;
+ // Perform callback
+ internalCallback(error_message, null, server);
+ } else if(server.isSetMember()) {
+ if(server.listeners("error") && server.listeners("error").length > 0) server.emit("error", error_message, server);
+ } else {
+ if(eventReceiver.listeners("error") && eventReceiver.listeners("error").length > 0) eventReceiver.emit("error", error_message, server);
+ }
+
+ // If we are a single server connection fire errors correctly
+ if(!server.isSetMember()) {
+ // Fire all callback errors
+ server.__executeAllCallbacksWithError(error_message);
+ // Emit error
+ server._emitAcrossAllDbInstances(server, eventReceiver, "error", error_message, server, true);
+ }
+
+ // If we have autoConnect enabled let's fire up an attempt to reconnect
+ if(server.isAutoReconnect()
+ && !server.isSetMember()
+ && (server._serverState != 'destroyed')
+ && !server._reconnectInProgreess) {
+
+ // Set the number of retries
+ server._reconnect_retries = server.db.numberOfRetries;
+ // Attempt reconnect
+ server._reconnectInProgreess = true;
+ setTimeout(__attemptReconnect(server), server.db.retryMiliSeconds);
+ }
+ });
+
+ // Handle close events
+ connectionPool.on("close", function() {
+ // If pool connection is already closed
+ if(server._serverState === 'disconnected'
+ || server._serverState === 'destroyed') return;
+ // Set server state to disconnected
+ server._serverState = 'disconnected';
+ // If we have a callback return the error
+ if(typeof callback == 'function') {
+ // ensure no callbacks get called twice
+ var internalCallback = callback;
+ callback = null;
+ // Perform callback
+ internalCallback(new Error("connection closed"), null, server);
+ } else if(server.isSetMember()) {
+ if(server.listeners("close") && server.listeners("close").length > 0) server.emit("close", new Error("connection closed"), server);
+ } else {
+ if(eventReceiver.listeners("close") && eventReceiver.listeners("close").length > 0) eventReceiver.emit("close", new Error("connection closed"), server);
+ }
+
+ // If we are a single server connection fire errors correctly
+ if(!server.isSetMember()) {
+ // Fire all callback errors
+ server.__executeAllCallbacksWithError(new Error("connection closed"));
+ // Emit error
+ server._emitAcrossAllDbInstances(server, eventReceiver, "close", server, null, true);
+ }
+
+ // If we have autoConnect enabled let's fire up an attempt to reconnect
+ if(server.isAutoReconnect()
+ && !server.isSetMember()
+ && (server._serverState != 'destroyed')
+ && !server._reconnectInProgreess) {
+
+ // Set the number of retries
+ server._reconnect_retries = server.db.numberOfRetries;
+ // Attempt reconnect
+ server._reconnectInProgreess = true;
+ setTimeout(__attemptReconnect(server), server.db.retryMiliSeconds);
+ }
+ });
+
+ /**
+ * @ignore
+ */
+ var __attemptReconnect = function(server) {
+ return function() {
+ // Attempt reconnect
+ server.connect(server.db, server.options, function(err, result) {
+ server._reconnect_retries = server._reconnect_retries - 1;
+
+ if(err) {
+ // Retry
+ if(server._reconnect_retries == 0 || server._serverState == 'destroyed') {
+ server._serverState = 'connected';
+ server._reconnectInProgreess = false
+ // Fire all callback errors
+ return server.__executeAllCallbacksWithError(new Error("failed to reconnect to server"));
+ } else {
+ return setTimeout(__attemptReconnect(server), server.db.retryMiliSeconds);
+ }
+ } else {
+ // Set as authenticating (isConnected will be false)
+ server._serverState = 'authenticating';
+ // Apply any auths, we don't try to catch any errors here
+ // as there are nowhere to simply propagate them to
+ self._apply_auths(server.db, function(err, result) {
+ server._serverState = 'connected';
+ server._reconnectInProgreess = false;
+ server._commandsStore.execute_queries();
+ server._commandsStore.execute_writes();
+ });
+ }
+ });
+ }
+ }
+
+ // If we have a parser error we are in an unknown state, close everything and emit
+ // error
+ connectionPool.on("parseError", function(message) {
+ // If pool connection is already closed
+ if(server._serverState === 'disconnected'
+ || server._serverState === 'destroyed') return;
+ // Set server state to disconnected
+ server._serverState = 'disconnected';
+ // If we have a callback return the error
+ if(typeof callback === 'function') {
+ // ensure no callbacks get called twice
+ var internalCallback = callback;
+ callback = null;
+ // Perform callback
+ internalCallback(new Error("connection closed due to parseError"), null, server);
+ } else if(server.isSetMember()) {
+ if(server.listeners("parseError") && server.listeners("parseError").length > 0) server.emit("parseError", new Error("connection closed due to parseError"), server);
+ } else {
+ if(eventReceiver.listeners("parseError") && eventReceiver.listeners("parseError").length > 0) eventReceiver.emit("parseError", new Error("connection closed due to parseError"), server);
+ }
+
+ // If we are a single server connection fire errors correctly
+ if(!server.isSetMember()) {
+ // Fire all callback errors
+ server.__executeAllCallbacksWithError(new Error("connection closed due to parseError"));
+ // Emit error
+ server._emitAcrossAllDbInstances(server, eventReceiver, "parseError", server, null, true);
+ }
+ });
+
+ // Boot up connection poole, pass in a locator of callbacks
+ connectionPool.start();
+}
+
+/**
+ * @ignore
+ */
+Server.prototype.allRawConnections = function() {
+ return this.connectionPool.getAllConnections();
+}
+
+/**
+ * Check if a writer can be provided
+ * @ignore
+ */
+var canCheckoutWriter = function(self, read) {
+ // We cannot write to an arbiter or secondary server
+ if(self.isMasterDoc && self.isMasterDoc['arbiterOnly'] == true) {
+ return new Error("Cannot write to an arbiter");
+ } if(self.isMasterDoc['secondary'] == true) {
+ return new Error("Cannot write to a secondary");
+ } else if(read == true && self._readPreference == ReadPreference.SECONDARY && self.isMasterDoc['ismaster'] == true) {
+ return new Error("Cannot read from primary when secondary only specified");
+ }
+
+ // Return no error
+ return null;
+}
+
+/**
+ * @ignore
+ */
+Server.prototype.checkoutWriter = function(read) {
+ if(read == true) return this.connectionPool.checkoutConnection();
+ // Check if are allowed to do a checkout (if we try to use an arbiter f.ex)
+ var result = canCheckoutWriter(this, read);
+ // If the result is null check out a writer
+ if(result == null && this.connectionPool != null) {
+ return this.connectionPool.checkoutConnection();
+ } else if(result == null) {
+ return null;
+ } else {
+ return result;
+ }
+}
+
+/**
+ * Check if a reader can be provided
+ * @ignore
+ */
+var canCheckoutReader = function(self) {
+ // We cannot write to an arbiter or secondary server
+ if(self.isMasterDoc && self.isMasterDoc['arbiterOnly'] == true) {
+ return new Error("Cannot write to an arbiter");
+ } else if(self._readPreference != null) {
+ // If the read preference is Primary and the instance is not a master return an error
+ if((self._readPreference == ReadPreference.PRIMARY) && self.isMasterDoc['ismaster'] != true) {
+ return new Error("Read preference is Server.PRIMARY and server is not master");
+ } else if(self._readPreference == ReadPreference.SECONDARY && self.isMasterDoc['ismaster'] == true) {
+ return new Error("Cannot read from primary when secondary only specified");
+ }
+ }
+
+ // Return no error
+ return null;
+}
+
+/**
+ * @ignore
+ */
+Server.prototype.checkoutReader = function(read) {
+ // Check if are allowed to do a checkout (if we try to use an arbiter f.ex)
+ var result = canCheckoutReader(this);
+ // If the result is null check out a writer
+ if(result == null && this.connectionPool != null) {
+ return this.connectionPool.checkoutConnection();
+ } else if(result == null) {
+ return null;
+ } else {
+ return result;
+ }
+}
+
+/**
+ * @ignore
+ */
+Server.prototype.enableRecordQueryStats = function(enable) {
+ this.recordQueryStats = enable;
+}
+
+/**
+ * Internal statistics object used for calculating average and standard devitation on
+ * running queries
+ * @ignore
+ */
+var RunningStats = function() {
+ var self = this;
+ this.m_n = 0;
+ this.m_oldM = 0.0;
+ this.m_oldS = 0.0;
+ this.m_newM = 0.0;
+ this.m_newS = 0.0;
+
+ // Define getters
+ Object.defineProperty(this, "numDataValues", { enumerable: true
+ , get: function () { return this.m_n; }
+ });
+
+ Object.defineProperty(this, "mean", { enumerable: true
+ , get: function () { return (this.m_n > 0) ? this.m_newM : 0.0; }
+ });
+
+ Object.defineProperty(this, "variance", { enumerable: true
+ , get: function () { return ((this.m_n > 1) ? this.m_newS/(this.m_n - 1) : 0.0); }
+ });
+
+ Object.defineProperty(this, "standardDeviation", { enumerable: true
+ , get: function () { return Math.sqrt(this.variance); }
+ });
+
+ Object.defineProperty(this, "sScore", { enumerable: true
+ , get: function () {
+ var bottom = this.mean + this.standardDeviation;
+ if(bottom == 0) return 0;
+ return ((2 * this.mean * this.standardDeviation)/(bottom));
+ }
+ });
+}
+
+/**
+ * @ignore
+ */
+RunningStats.prototype.push = function(x) {
+ // Update the number of samples
+ this.m_n = this.m_n + 1;
+ // See Knuth TAOCP vol 2, 3rd edition, page 232
+ if(this.m_n == 1) {
+ this.m_oldM = this.m_newM = x;
+ this.m_oldS = 0.0;
+ } else {
+ this.m_newM = this.m_oldM + (x - this.m_oldM) / this.m_n;
+ this.m_newS = this.m_oldS + (x - this.m_oldM) * (x - this.m_newM);
+
+ // set up for next iteration
+ this.m_oldM = this.m_newM;
+ this.m_oldS = this.m_newS;
+ }
+}
+
+/**
+ * @ignore
+ */
+Object.defineProperty(Server.prototype, "autoReconnect", { enumerable: true
+ , get: function () {
+ return this.options['auto_reconnect'] == null ? false : this.options['auto_reconnect'];
+ }
+});
+
+/**
+ * @ignore
+ */
+Object.defineProperty(Server.prototype, "connection", { enumerable: true
+ , get: function () {
+ return this.internalConnection;
+ }
+ , set: function(connection) {
+ this.internalConnection = connection;
+ }
+});
+
+/**
+ * @ignore
+ */
+Object.defineProperty(Server.prototype, "master", { enumerable: true
+ , get: function () {
+ return this.internalMaster;
+ }
+ , set: function(value) {
+ this.internalMaster = value;
+ }
+});
+
+/**
+ * @ignore
+ */
+Object.defineProperty(Server.prototype, "primary", { enumerable: true
+ , get: function () {
+ return this;
+ }
+});
+
+/**
+ * Getter for query Stats
+ * @ignore
+ */
+Object.defineProperty(Server.prototype, "queryStats", { enumerable: true
+ , get: function () {
+ return this._state.runtimeStats.queryStats;
+ }
+});
+
+/**
+ * @ignore
+ */
+Object.defineProperty(Server.prototype, "runtimeStats", { enumerable: true
+ , get: function () {
+ return this._state.runtimeStats;
+ }
+});
+
+/**
+ * Get Read Preference method
+ * @ignore
+ */
+Object.defineProperty(Server.prototype, "readPreference", { enumerable: true
+ , get: function () {
+ if(this._readPreference == null && this.readSecondary) {
+ return Server.READ_SECONDARY;
+ } else if(this._readPreference == null && !this.readSecondary) {
+ return Server.READ_PRIMARY;
+ } else {
+ return this._readPreference;
+ }
+ }
+});
+
+/**
+ * @ignore
+ */
+exports.Server = Server;
diff --git a/node_modules/mongodb/lib/mongodb/connection/url_parser.js b/node_modules/mongodb/lib/mongodb/connection/url_parser.js
new file mode 100644
index 0000000..9adf526
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/connection/url_parser.js
@@ -0,0 +1,241 @@
+var fs = require('fs'),
+ ReadPreference = require('./read_preference').ReadPreference;
+
+exports.parse = function(url, options) {
+ // Ensure we have a default options object if none set
+ options = options || {};
+ // Variables
+ var connection_part = '';
+ var auth_part = '';
+ var query_string_part = '';
+ var dbName = 'admin';
+
+ // Must start with mongodb
+ if(url.indexOf("mongodb://") != 0)
+ throw Error("URL must be in the format mongodb://user:pass@host:port/dbname");
+ // If we have a ? mark cut the query elements off
+ if(url.indexOf("?") != -1) {
+ query_string_part = url.substr(url.indexOf("?") + 1);
+ connection_part = url.substring("mongodb://".length, url.indexOf("?"))
+ } else {
+ connection_part = url.substring("mongodb://".length);
+ }
+
+ // Check if we have auth params
+ if(connection_part.indexOf("@") != -1) {
+ auth_part = connection_part.split("@")[0];
+ connection_part = connection_part.split("@")[1];
+ }
+
+ // Check if the connection string has a db
+ if(connection_part.indexOf(".sock") != -1) {
+ if(connection_part.indexOf(".sock/") != -1) {
+ dbName = connection_part.split(".sock/")[1];
+ connection_part = connection_part.split("/", connection_part.indexOf(".sock") + ".sock".length);
+ }
+ } else if(connection_part.indexOf("/") != -1) {
+ dbName = connection_part.split("/")[1];
+ connection_part = connection_part.split("/")[0];
+ }
+
+ // Result object
+ var object = {};
+
+ // Pick apart the authentication part of the string
+ var authPart = auth_part || '';
+ var auth = authPart.split(':', 2);
+ if(options['uri_decode_auth']){
+ auth[0] = decodeURIComponent(auth[0]);
+ if(auth[1]){
+ auth[1] = decodeURIComponent(auth[1]);
+ }
+ }
+
+ // Add auth to final object if we have 2 elements
+ if(auth.length == 2) object.auth = {user: auth[0], password: auth[1]};
+
+ // Variables used for temporary storage
+ var hostPart;
+ var urlOptions;
+ var servers;
+ var serverOptions = {socketOptions: {}};
+ var dbOptions = {read_preference_tags: []};
+ var replSetServersOptions = {socketOptions: {}};
+ // Add server options to final object
+ object.server_options = serverOptions;
+ object.db_options = dbOptions;
+ object.rs_options = replSetServersOptions;
+ object.mongos_options = {};
+
+ // Let's check if we are using a domain socket
+ if(url.match(/\.sock/)) {
+ // Split out the socket part
+ var domainSocket = url.substring(
+ url.indexOf("mongodb://") + "mongodb://".length
+ , url.lastIndexOf(".sock") + ".sock".length);
+ // Clean out any auth stuff if any
+ if(domainSocket.indexOf("@") != -1) domainSocket = domainSocket.split("@")[1];
+ servers = [{domain_socket: domainSocket}];
+ } else {
+ // Split up the db
+ hostPart = connection_part;
+ // Parse all server results
+ servers = hostPart.split(',').map(function(h) {
+ var hostPort = h.split(':', 2);
+ var _host = hostPort[0] || 'localhost';
+ var _port = hostPort[1] != null ? parseInt(hostPort[1], 10) : 27017;
+ // Check for localhost?safe=true style case
+ if(_host.indexOf("?") != -1) _host = _host.split(/\?/)[0];
+
+ // Return the mapped object
+ return {host: _host, port: _port};
+ });
+ }
+
+ // Get the db name
+ object.dbName = dbName || 'admin';
+ // Split up all the options
+ urlOptions = (query_string_part || '').split(/[&;]/);
+ // Ugh, we have to figure out which options go to which constructor manually.
+ urlOptions.forEach(function(opt) {
+ if(!opt) return;
+ var splitOpt = opt.split('='), name = splitOpt[0], value = splitOpt[1];
+ // Options implementations
+ switch(name) {
+ case 'slaveOk':
+ case 'slave_ok':
+ serverOptions.slave_ok = (value == 'true');
+ break;
+ case 'maxPoolSize':
+ case 'poolSize':
+ serverOptions.poolSize = parseInt(value, 10);
+ replSetServersOptions.poolSize = parseInt(value, 10);
+ break;
+ case 'autoReconnect':
+ case 'auto_reconnect':
+ serverOptions.auto_reconnect = (value == 'true');
+ break;
+ case 'minPoolSize':
+ throw new Error("minPoolSize not supported");
+ case 'maxIdleTimeMS':
+ throw new Error("maxIdleTimeMS not supported");
+ case 'waitQueueMultiple':
+ throw new Error("waitQueueMultiple not supported");
+ case 'waitQueueTimeoutMS':
+ throw new Error("waitQueueTimeoutMS not supported");
+ case 'uuidRepresentation':
+ throw new Error("uuidRepresentation not supported");
+ case 'ssl':
+ if(value == 'prefer') {
+ serverOptions.ssl = value;
+ replSetServersOptions.ssl = value;
+ break;
+ }
+ serverOptions.ssl = (value == 'true');
+ replSetServersOptions.ssl = (value == 'true');
+ break;
+ case 'replicaSet':
+ case 'rs_name':
+ replSetServersOptions.rs_name = value;
+ break;
+ case 'reconnectWait':
+ replSetServersOptions.reconnectWait = parseInt(value, 10);
+ break;
+ case 'retries':
+ replSetServersOptions.retries = parseInt(value, 10);
+ break;
+ case 'readSecondary':
+ case 'read_secondary':
+ replSetServersOptions.read_secondary = (value == 'true');
+ break;
+ case 'fsync':
+ dbOptions.fsync = (value == 'true');
+ break;
+ case 'journal':
+ dbOptions.journal = (value == 'true');
+ break;
+ case 'safe':
+ dbOptions.safe = (value == 'true');
+ break;
+ case 'nativeParser':
+ case 'native_parser':
+ dbOptions.native_parser = (value == 'true');
+ break;
+ case 'connectTimeoutMS':
+ serverOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
+ replSetServersOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
+ break;
+ case 'socketTimeoutMS':
+ serverOptions.socketOptions.socketTimeoutMS = parseInt(value, 10);
+ replSetServersOptions.socketOptions.socketTimeoutMS = parseInt(value, 10);
+ break;
+ case 'w':
+ dbOptions.w = parseInt(value, 10);
+ break;
+ case 'authSource':
+ dbOptions.authSource = value;
+ break;
+ case 'authMechanism':
+ if(value == 'GSSAPI') {
+ // If no password provided decode only the principal
+ if(object.auth == null) {
+ var urlDecodeAuthPart = decodeURIComponent(authPart);
+ if(urlDecodeAuthPart.indexOf("@") == -1) throw new Error("GSSAPI requires a provided principal");
+ object.auth = {user: urlDecodeAuthPart, password: null};
+ } else {
+ object.auth.user = decodeURIComponent(object.auth.user);
+ }
+ }
+ // Only support GSSAPI or MONGODB-CR for now
+ if(value != 'GSSAPI' && value != 'MONGODB-CR') throw new Error("only GSSAPI or MONGODB-CR is supported by authMechanism");
+ dbOptions.authMechanism = value;
+ break;
+ case 'wtimeoutMS':
+ dbOptions.wtimeoutMS = parseInt(value, 10);
+ break;
+ case 'readPreference':
+ if(!ReadPreference.isValid(value)) throw new Error("readPreference must be either primary/primaryPreferred/secondary/secondaryPreferred/nearest");
+ dbOptions.read_preference = value;
+ break;
+ case 'readPreferenceTags':
+ // Contains the tag object
+ var tagObject = {};
+ if(value == null || value == '') {
+ dbOptions.read_preference_tags.push(tagObject);
+ break;
+ }
+
+ // Split up the tags
+ var tags = value.split(/\,/);
+ for(var i = 0; i < tags.length; i++) {
+ var parts = tags[i].trim().split(/\:/);
+ tagObject[parts[0]] = parts[1];
+ }
+
+ // Set the preferences tags
+ dbOptions.read_preference_tags.push(tagObject);
+ break;
+ default:
+ break;
+ }
+ });
+
+ // No tags: should be null (not [])
+ if(dbOptions.read_preference_tags.length === 0) {
+ dbOptions.read_preference_tags = null;
+ }
+
+ // Validate if there are an invalid write concern combinations
+ if((dbOptions.w == -1 || dbOptions.w == 0) && (
+ dbOptions.journal == true
+ || dbOptions.fsync == true
+ || dbOptions.safe == true)) throw new Error("w set to -1 or 0 cannot be combined with safe/w/journal/fsync")
+
+ // If no read preference set it to primary
+ if(!dbOptions.read_preference) dbOptions.read_preference = 'primary';
+
+ // Add servers to result
+ object.servers = servers;
+ // Returned parsed object
+ return object;
+}
diff --git a/node_modules/mongodb/lib/mongodb/cursor.js b/node_modules/mongodb/lib/mongodb/cursor.js
new file mode 100644
index 0000000..5eab489
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/cursor.js
@@ -0,0 +1,938 @@
+var QueryCommand = require('./commands/query_command').QueryCommand,
+ GetMoreCommand = require('./commands/get_more_command').GetMoreCommand,
+ KillCursorCommand = require('./commands/kill_cursor_command').KillCursorCommand,
+ Long = require('bson').Long,
+ ReadPreference = require('./connection/read_preference').ReadPreference,
+ CursorStream = require('./cursorstream'),
+ timers = require('timers'),
+ utils = require('./utils');
+
+// Set processor, setImmediate if 0.10 otherwise nextTick
+var processor = timers.setImmediate ? timers.setImmediate : process.nextTick;
+
+/**
+ * Constructor for a cursor object that handles all the operations on query result
+ * using find. This cursor object is unidirectional and cannot traverse backwards. Clients should not be creating a cursor directly,
+ * but use find to acquire a cursor. (INTERNAL TYPE)
+ *
+ * Options
+ * - **skip** {Number} skip number of documents to skip.
+ * - **limit** {Number}, limit the number of results to return. -1 has a special meaning and is used by Db.eval. A value of 1 will also be treated as if it were -1.
+ * - **sort** {Array | Object}, set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc.
+ * - **hint** {Object}, hint force the query to use a specific index.
+ * - **explain** {Boolean}, explain return the explaination of the query.
+ * - **snapshot** {Boolean}, snapshot Snapshot mode assures no duplicates are returned.
+ * - **timeout** {Boolean}, timeout allow the query to timeout.
+ * - **tailable** {Boolean}, tailable allow the cursor to be tailable.
+ * - **awaitdata** {Boolean}, awaitdata allow the cursor to wait for data, only applicable for tailable cursor.
+ * - **batchSize** {Number}, batchSize the number of the subset of results to request the database to return for every request. This should initially be greater than 1 otherwise the database will automatically close the cursor. The batch size can be set to 1 with cursorInstance.batchSize after performing the initial query to the database.
+ * - **raw** {Boolean}, raw return all query documents as raw buffers (default false).
+ * - **read** {Boolean}, read specify override of read from source (primary/secondary).
+ * - **returnKey** {Boolean}, returnKey only return the index key.
+ * - **maxScan** {Number}, maxScan limit the number of items to scan.
+ * - **min** {Number}, min set index bounds.
+ * - **max** {Number}, max set index bounds.
+ * - **showDiskLoc** {Boolean}, showDiskLoc show disk location of results.
+ * - **comment** {String}, comment you can put a $comment field on a query to make looking in the profiler logs simpler.
+ * - **numberOfRetries** {Number}, numberOfRetries if using awaidata specifies the number of times to retry on timeout.
+ * - **dbName** {String}, dbName override the default dbName.
+ * - **tailableRetryInterval** {Number}, tailableRetryInterval specify the miliseconds between getMores on tailable cursor.
+ * - **exhaust** {Boolean}, exhaust have the server send all the documents at once as getMore packets.
+ * - **partial** {Boolean}, partial have the sharded system return a partial result from mongos.
+ *
+ * @class Represents a Cursor.
+ * @param {Db} db the database object to work with.
+ * @param {Collection} collection the collection to query.
+ * @param {Object} selector the query selector.
+ * @param {Object} fields an object containing what fields to include or exclude from objects returned.
+ * @param {Object} [options] additional options for the collection.
+*/
+function Cursor(db, collection, selector, fields, options) {
+ this.db = db;
+ this.collection = collection;
+ this.selector = selector;
+ this.fields = fields;
+ options = !options ? {} : options;
+
+ this.skipValue = options.skip == null ? 0 : options.skip;
+ this.limitValue = options.limit == null ? 0 : options.limit;
+ this.sortValue = options.sort;
+ this.hint = options.hint;
+ this.explainValue = options.explain;
+ this.snapshot = options.snapshot;
+ this.timeout = options.timeout == null ? true : options.timeout;
+ this.tailable = options.tailable;
+ this.awaitdata = options.awaitdata;
+ this.numberOfRetries = options.numberOfRetries == null ? 5 : options.numberOfRetries;
+ this.currentNumberOfRetries = this.numberOfRetries;
+ this.batchSizeValue = options.batchSize == null ? 0 : options.batchSize;
+ this.raw = options.raw == null ? false : options.raw;
+ this.read = options.read == null ? ReadPreference.PRIMARY : options.read;
+ this.returnKey = options.returnKey;
+ this.maxScan = options.maxScan;
+ this.min = options.min;
+ this.max = options.max;
+ this.showDiskLoc = options.showDiskLoc;
+ this.comment = options.comment;
+ this.tailableRetryInterval = options.tailableRetryInterval || 100;
+ this.exhaust = options.exhaust || false;
+ this.partial = options.partial || false;
+ this.slaveOk = options.slaveOk || false;
+
+ this.totalNumberOfRecords = 0;
+ this.items = [];
+ this.cursorId = Long.fromInt(0);
+
+ // This name
+ this.dbName = options.dbName;
+
+ // State variables for the cursor
+ this.state = Cursor.INIT;
+ // Keep track of the current query run
+ this.queryRun = false;
+ this.getMoreTimer = false;
+
+ // If we are using a specific db execute against it
+ if(this.dbName != null) {
+ this.collectionName = this.dbName + "." + this.collection.collectionName;
+ } else {
+ this.collectionName = (this.db.databaseName ? this.db.databaseName + "." : '') + this.collection.collectionName;
+ }
+};
+
+/**
+ * Resets this cursor to its initial state. All settings like the query string,
+ * tailable, batchSizeValue, skipValue and limits are preserved.
+ *
+ * @return {Cursor} returns itself with rewind applied.
+ * @api public
+ */
+Cursor.prototype.rewind = function() {
+ var self = this;
+
+ if (self.state != Cursor.INIT) {
+ if (self.state != Cursor.CLOSED) {
+ self.close(function() {});
+ }
+
+ self.numberOfReturned = 0;
+ self.totalNumberOfRecords = 0;
+ self.items = [];
+ self.cursorId = Long.fromInt(0);
+ self.state = Cursor.INIT;
+ self.queryRun = false;
+ }
+
+ return self;
+};
+
+
+/**
+ * Returns an array of documents. The caller is responsible for making sure that there
+ * is enough memory to store the results. Note that the array only contain partial
+ * results when this cursor had been previouly accessed. In that case,
+ * cursor.rewind() can be used to reset the cursor.
+ *
+ * @param {Function} callback This will be called after executing this method successfully. The first parameter will contain the Error object if an error occured, or null otherwise. The second parameter will contain an array of BSON deserialized objects as a result of the query.
+ * @return {null}
+ * @api public
+ */
+Cursor.prototype.toArray = function(callback) {
+ var self = this;
+
+ if(!callback) {
+ throw new Error('callback is mandatory');
+ }
+
+ if(this.tailable) {
+ callback(new Error("Tailable cursor cannot be converted to array"), null);
+ } else if(this.state != Cursor.CLOSED) {
+ // return toArrayExhaust(self, callback);
+ // If we are using exhaust we can't use the quick fire method
+ if(self.exhaust) return toArrayExhaust(self, callback);
+ // Quick fire using trampoline to avoid nextTick
+ self.nextObject({noReturn: true}, function(err, result) {
+ if(err) return callback(utils.toError(err), null);
+ if(self.cursorId.toString() == "0") {
+ self.state = Cursor.CLOSED;
+ return callback(null, self.items);
+ }
+
+ // Let's issue getMores until we have no more records waiting
+ getAllByGetMore(self, function(err, done) {
+ self.state = Cursor.CLOSED;
+ if(err) return callback(utils.toError(err), null);
+ // Let's release the internal list
+ var items = self.items;
+ self.items = null;
+ // Return all the items
+ callback(null, items);
+ });
+ })
+
+ } else {
+ callback(new Error("Cursor is closed"), null);
+ }
+}
+
+var toArrayExhaust = function(self, callback) {
+ var items = [];
+
+ self.each(function(err, item) {
+ if(err != null) {
+ return callback(utils.toError(err), null);
+ }
+
+ if(item != null && Array.isArray(items)) {
+ items.push(item);
+ } else {
+ var resultItems = items;
+ items = null;
+ self.items = [];
+ callback(null, resultItems);
+ }
+ });
+}
+
+var getAllByGetMore = function(self, callback) {
+ getMore(self, {noReturn: true}, function(err, result) {
+ if(err) return callback(utils.toError(err));
+ if(result == null) return callback(null, null);
+ if(self.cursorId.toString() == "0") return callback(null, null);
+ getAllByGetMore(self, callback);
+ })
+}
+
+/**
+ * Iterates over all the documents for this cursor. As with **{cursor.toArray}**,
+ * not all of the elements will be iterated if this cursor had been previouly accessed.
+ * In that case, **{cursor.rewind}** can be used to reset the cursor. However, unlike
+ * **{cursor.toArray}**, the cursor will only hold a maximum of batch size elements
+ * at any given time if batch size is specified. Otherwise, the caller is responsible
+ * for making sure that the entire result can fit the memory.
+ *
+ * @param {Function} callback this will be called for while iterating every document of the query result. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the document.
+ * @return {null}
+ * @api public
+ */
+Cursor.prototype.each = function(callback) {
+ var self = this;
+ var fn;
+
+ if (!callback) {
+ throw new Error('callback is mandatory');
+ }
+
+ if(this.state != Cursor.CLOSED) {
+ // If we are using exhaust we can't use the quick fire method
+ if(self.exhaust) return eachExhaust(self, callback);
+ // Quick fire using trampoline to avoid nextTick
+ if(this.items.length > 0) {
+ // Trampoline all the entries
+ while(fn = loop(self, callback)) fn(self, callback);
+ // Call each again
+ self.each(callback);
+ } else {
+ self.nextObject(function(err, item) {
+
+ if(err) {
+ self.state = Cursor.CLOSED;
+ return callback(utils.toError(err), item);
+ }
+
+ if(item == null) return callback(null, null);
+ callback(null, item);
+ self.each(callback);
+ })
+ }
+ } else {
+ callback(new Error("Cursor is closed"), null);
+ }
+}
+
+// Special for exhaust command as we don't initiate the actual result sets
+// the server just sends them as they arrive meaning we need to get the IO event
+// loop happen so we can receive more data from the socket or we return to early
+// after the first fetch and loose all the incoming getMore's automatically issued
+// from the server.
+var eachExhaust = function(self, callback) {
+ //FIX: stack overflow (on deep callback) (cred: https://github.com/limp/node-mongodb-native/commit/27da7e4b2af02035847f262b29837a94bbbf6ce2)
+ processor(function(){
+ // Fetch the next object until there is no more objects
+ self.nextObject(function(err, item) {
+ if(err != null) return callback(err, null);
+ if(item != null) {
+ callback(null, item);
+ eachExhaust(self, callback);
+ } else {
+ // Close the cursor if done
+ self.state = Cursor.CLOSED;
+ callback(err, null);
+ }
+ });
+ });
+}
+
+// Trampoline emptying the number of retrieved items
+// without incurring a nextTick operation
+var loop = function(self, callback) {
+ // No more items we are done
+ if(self.items.length == 0) return;
+ // Get the next document
+ var doc = self.items.shift();
+ // Callback
+ callback(null, doc);
+ // Loop
+ return loop;
+}
+
+/**
+ * Determines how many result the query for this cursor will return
+ *
+ * @param {Boolean} applySkipLimit if set to true will apply the skip and limits set on the cursor. Defaults to false.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the number of results or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Cursor.prototype.count = function(applySkipLimit, callback) {
+ if(typeof applySkipLimit == 'function') {
+ callback = applySkipLimit;
+ applySkipLimit = false;
+ }
+
+ var options = {};
+ if(applySkipLimit) {
+ if(typeof this.skipValue == 'number') options.skip = this.skipValue;
+ if(typeof this.limitValue == 'number') options.limit = this.limitValue;
+ }
+
+ // Call count command
+ this.collection.count(this.selector, options, callback);
+};
+
+/**
+ * Sets the sort parameter of this cursor to the given value.
+ *
+ * This method has the following method signatures:
+ * (keyOrList, callback)
+ * (keyOrList, direction, callback)
+ *
+ * @param {String|Array|Object} keyOrList This can be a string or an array. If passed as a string, the string will be the field to sort. If passed an array, each element will represent a field to be sorted and should be an array that contains the format [string, direction].
+ * @param {String|Number} direction this determines how the results are sorted. "asc", "ascending" or 1 for asceding order while "desc", "desceding or -1 for descending order. Note that the strings are case insensitive.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain an error object when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
+ * @return {Cursor} an instance of this object.
+ * @api public
+ */
+Cursor.prototype.sort = function(keyOrList, direction, callback) {
+ callback = callback || function(){};
+ if(typeof direction === "function") { callback = direction; direction = null; }
+
+ if(this.tailable) {
+ callback(new Error("Tailable cursor doesn't support sorting"), null);
+ } else if(this.queryRun == true || this.state == Cursor.CLOSED) {
+ callback(new Error("Cursor is closed"), null);
+ } else {
+ var order = keyOrList;
+
+ if(direction != null) {
+ order = [[keyOrList, direction]];
+ }
+
+ this.sortValue = order;
+ callback(null, this);
+ }
+ return this;
+};
+
+/**
+ * Sets the limit parameter of this cursor to the given value.
+ *
+ * @param {Number} limit the new limit.
+ * @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the limit given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
+ * @return {Cursor} an instance of this object.
+ * @api public
+ */
+Cursor.prototype.limit = function(limit, callback) {
+ if(this.tailable) {
+ if(callback) {
+ callback(new Error("Tailable cursor doesn't support limit"), null);
+ } else {
+ throw new Error("Tailable cursor doesn't support limit");
+ }
+ } else if(this.queryRun == true || this.state == Cursor.CLOSED) {
+ if(callback) {
+ callback(new Error("Cursor is closed"), null);
+ } else {
+ throw new Error("Cursor is closed");
+ }
+ } else {
+ if(limit != null && limit.constructor != Number) {
+ if(callback) {
+ callback(new Error("limit requires an integer"), null);
+ } else {
+ throw new Error("limit requires an integer");
+ }
+ } else {
+ this.limitValue = limit;
+ if(callback) return callback(null, this);
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Sets the read preference for the cursor
+ *
+ * @param {String} the read preference for the cursor, one of Server.READ_PRIMARY, Server.READ_SECONDARY, Server.READ_SECONDARY_ONLY
+ * @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the read preference given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
+ * @return {Cursor} an instance of this object.
+ * @api public
+ */
+Cursor.prototype.setReadPreference = function(readPreference, tags, callback) {
+ if(typeof tags == 'function') callback = tags;
+
+ var _mode = readPreference != null && typeof readPreference == 'object' ? readPreference.mode : readPreference;
+
+ if(this.queryRun == true || this.state == Cursor.CLOSED) {
+ if(callback == null) throw new Error("Cannot change read preference on executed query or closed cursor");
+ callback(new Error("Cannot change read preference on executed query or closed cursor"));
+ } else if(_mode != null && _mode != 'primary'
+ && _mode != 'secondaryOnly' && _mode != 'secondary'
+ && _mode != 'nearest' && _mode != 'primaryPreferred' && _mode != 'secondaryPreferred') {
+ if(callback == null) throw new Error("only readPreference of primary, secondary, secondaryPreferred, primaryPreferred or nearest supported");
+ callback(new Error("only readPreference of primary, secondary, secondaryPreferred, primaryPreferred or nearest supported"));
+ } else {
+ this.read = readPreference;
+ if(callback != null) callback(null, this);
+ }
+
+ return this;
+}
+
+/**
+ * Sets the skip parameter of this cursor to the given value.
+ *
+ * @param {Number} skip the new skip value.
+ * @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the skip value given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
+ * @return {Cursor} an instance of this object.
+ * @api public
+ */
+Cursor.prototype.skip = function(skip, callback) {
+ callback = callback || function(){};
+
+ if(this.tailable) {
+ callback(new Error("Tailable cursor doesn't support skip"), null);
+ } else if(this.queryRun == true || this.state == Cursor.CLOSED) {
+ callback(new Error("Cursor is closed"), null);
+ } else {
+ if(skip != null && skip.constructor != Number) {
+ callback(new Error("skip requires an integer"), null);
+ } else {
+ this.skipValue = skip;
+ callback(null, this);
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Sets the batch size parameter of this cursor to the given value.
+ *
+ * @param {Number} batchSize the new batch size.
+ * @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the batchSize given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
+ * @return {Cursor} an instance of this object.
+ * @api public
+ */
+Cursor.prototype.batchSize = function(batchSize, callback) {
+ if(this.state == Cursor.CLOSED) {
+ if(callback != null) {
+ return callback(new Error("Cursor is closed"), null);
+ } else {
+ throw new Error("Cursor is closed");
+ }
+ } else if(batchSize != null && batchSize.constructor != Number) {
+ if(callback != null) {
+ return callback(new Error("batchSize requires an integer"), null);
+ } else {
+ throw new Error("batchSize requires an integer");
+ }
+ } else {
+ this.batchSizeValue = batchSize;
+ if(callback != null) return callback(null, this);
+ }
+
+ return this;
+};
+
+/**
+ * The limit used for the getMore command
+ *
+ * @return {Number} The number of records to request per batch.
+ * @ignore
+ * @api private
+ */
+var limitRequest = function(self) {
+ var requestedLimit = self.limitValue;
+ var absLimitValue = Math.abs(self.limitValue);
+ var absBatchValue = Math.abs(self.batchSizeValue);
+
+ if(absLimitValue > 0) {
+ if (absBatchValue > 0) {
+ requestedLimit = Math.min(absLimitValue, absBatchValue);
+ }
+ } else {
+ requestedLimit = self.batchSizeValue;
+ }
+
+ return requestedLimit;
+};
+
+
+/**
+ * Generates a QueryCommand object using the parameters of this cursor.
+ *
+ * @return {QueryCommand} The command object
+ * @ignore
+ * @api private
+ */
+var generateQueryCommand = function(self) {
+ // Unpack the options
+ var queryOptions = QueryCommand.OPTS_NONE;
+ if(!self.timeout) {
+ queryOptions |= QueryCommand.OPTS_NO_CURSOR_TIMEOUT;
+ }
+
+ if(self.tailable != null) {
+ queryOptions |= QueryCommand.OPTS_TAILABLE_CURSOR;
+ self.skipValue = self.limitValue = 0;
+
+ // if awaitdata is set
+ if(self.awaitdata != null) {
+ queryOptions |= QueryCommand.OPTS_AWAIT_DATA;
+ }
+ }
+
+ if(self.exhaust) {
+ queryOptions |= QueryCommand.OPTS_EXHAUST;
+ }
+
+ // Unpack the read preference to set slave ok correctly
+ var read = self.read instanceof ReadPreference ? self.read.mode : self.read;
+
+ // if(self.read == 'secondary')
+ if(read == ReadPreference.PRIMARY_PREFERRED
+ || read == ReadPreference.SECONDARY
+ || read == ReadPreference.SECONDARY_PREFERRED
+ || read == ReadPreference.NEAREST) {
+ queryOptions |= QueryCommand.OPTS_SLAVE;
+ }
+
+ // Override slaveOk from the user
+ if(self.slaveOk) {
+ queryOptions |= QueryCommand.OPTS_SLAVE;
+ }
+
+ if(self.partial) {
+ queryOptions |= QueryCommand.OPTS_PARTIAL;
+ }
+
+ // limitValue of -1 is a special case used by Db#eval
+ var numberToReturn = self.limitValue == -1 ? -1 : limitRequest(self);
+
+ // Check if we need a special selector
+ if(self.sortValue != null || self.explainValue != null || self.hint != null || self.snapshot != null
+ || self.returnKey != null || self.maxScan != null || self.min != null || self.max != null
+ || self.showDiskLoc != null || self.comment != null) {
+
+ // Build special selector
+ var specialSelector = {'$query':self.selector};
+ if(self.sortValue != null) specialSelector['orderby'] = utils.formattedOrderClause(self.sortValue);
+ if(self.hint != null && self.hint.constructor == Object) specialSelector['$hint'] = self.hint;
+ if(self.snapshot != null) specialSelector['$snapshot'] = true;
+ if(self.returnKey != null) specialSelector['$returnKey'] = self.returnKey;
+ if(self.maxScan != null) specialSelector['$maxScan'] = self.maxScan;
+ if(self.min != null) specialSelector['$min'] = self.min;
+ if(self.max != null) specialSelector['$max'] = self.max;
+ if(self.showDiskLoc != null) specialSelector['$showDiskLoc'] = self.showDiskLoc;
+ if(self.comment != null) specialSelector['$comment'] = self.comment;
+ // If we have explain set only return a single document with automatic cursor close
+ if(self.explainValue != null) {
+ numberToReturn = (-1)*Math.abs(numberToReturn);
+ specialSelector['$explain'] = true;
+ }
+
+ // Return the query
+ return new QueryCommand(self.db, self.collectionName, queryOptions, self.skipValue, numberToReturn, specialSelector, self.fields);
+ } else {
+ return new QueryCommand(self.db, self.collectionName, queryOptions, self.skipValue, numberToReturn, self.selector, self.fields);
+ }
+};
+
+/**
+ * @return {Object} Returns an object containing the sort value of this cursor with
+ * the proper formatting that can be used internally in this cursor.
+ * @ignore
+ * @api private
+ */
+Cursor.prototype.formattedOrderClause = function() {
+ return utils.formattedOrderClause(this.sortValue);
+};
+
+/**
+ * Converts the value of the sort direction into its equivalent numerical value.
+ *
+ * @param sortDirection {String|number} Range of acceptable values:
+ * 'ascending', 'descending', 'asc', 'desc', 1, -1
+ *
+ * @return {number} The equivalent numerical value
+ * @throws Error if the given sortDirection is invalid
+ * @ignore
+ * @api private
+ */
+Cursor.prototype.formatSortValue = function(sortDirection) {
+ return utils.formatSortValue(sortDirection);
+};
+
+/**
+ * Gets the next document from the cursor.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain an error object on error while the second parameter will contain a document from the returned result or null if there are no more results.
+ * @api public
+ */
+Cursor.prototype.nextObject = function(options, callback) {
+ var self = this;
+
+ if(typeof options == 'function') {
+ callback = options;
+ options = {};
+ }
+
+ if(self.state == Cursor.INIT) {
+ var cmd;
+ try {
+ cmd = generateQueryCommand(self);
+ } catch (err) {
+ return callback(err, null);
+ }
+
+ var queryOptions = {exhaust: self.exhaust, raw:self.raw, read:self.read, connection:self.connection};
+ // Execute command
+ var commandHandler = function(err, result) {
+ // If on reconnect, the command got given a different connection, switch
+ // the whole cursor to it.
+ self.connection = queryOptions.connection;
+ self.state = Cursor.OPEN;
+ if(err != null && result == null) return callback(utils.toError(err), null);
+
+ if(err == null && (result == null || result.documents == null)) {
+ return self.close(function() {callback(null, null);});
+ }
+
+ if(err == null && result && result.documents[0] && result.documents[0]['$err']) {
+ return self.close(function() {callback(utils.toError(result.documents[0]['$err']), null);});
+ }
+
+ self.queryRun = true;
+ self.state = Cursor.OPEN; // Adjust the state of the cursor
+ self.cursorId = result.cursorId;
+ self.totalNumberOfRecords = result.numberReturned;
+
+ // Add the new documents to the list of items, using forloop to avoid
+ // new array allocations and copying
+ for(var i = 0; i < result.documents.length; i++) {
+ self.items.push(result.documents[i]);
+ }
+
+ // If we have noReturn set just return (not modifying the internal item list)
+ // used for toArray
+ if(options.noReturn) {
+ return callback(null, true);
+ }
+
+ // Ignore callbacks until the cursor is dead for exhausted
+ if(self.exhaust && result.cursorId.toString() == "0") {
+ self.nextObject(callback);
+ } else if(self.exhaust == false || self.exhaust == null) {
+ self.nextObject(callback);
+ }
+ };
+
+ // If we have no connection set on this cursor check one out
+ if(self.connection == null) {
+ try {
+ // self.connection = this.read == null ? self.db.serverConfig.checkoutWriter() : self.db.serverConfig.checkoutReader(this.read);
+ self.connection = self.db.serverConfig.checkoutReader(this.read);
+ } catch(err) {
+ return callback(utils.toError(err), null);
+ }
+ }
+
+ // Execute the command
+ self.db._executeQueryCommand(cmd, queryOptions, commandHandler);
+ // Set the command handler to null
+ commandHandler = null;
+ } else if(self.items.length) {
+ callback(null, self.items.shift());
+ } else if(self.cursorId.greaterThan(Long.fromInt(0))) {
+ getMore(self, callback);
+ } else {
+ // Force cursor to stay open
+ return self.close(function() {callback(null, null);});
+ }
+}
+
+/**
+ * Gets more results from the database if any.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain an error object on error while the second parameter will contain a document from the returned result or null if there are no more results.
+ * @ignore
+ * @api private
+ */
+var getMore = function(self, options, callback) {
+ var limit = 0;
+
+ if(typeof options == 'function') {
+ callback = options;
+ options = {};
+ }
+
+ if(self.state == Cursor.GET_MORE) return callback(null, null);
+
+ // Set get more in progress
+ self.state = Cursor.GET_MORE;
+
+ // Set options
+ if (!self.tailable && self.limitValue > 0) {
+ limit = self.limitValue - self.totalNumberOfRecords;
+ if (limit < 1) {
+ self.close(function() {callback(null, null);});
+ return;
+ }
+ }
+
+ try {
+ var getMoreCommand = new GetMoreCommand(
+ self.db
+ , self.collectionName
+ , limitRequest(self)
+ , self.cursorId
+ );
+
+ // Set up options
+ var command_options = {read: self.read, raw: self.raw, connection:self.connection };
+
+ // Execute the command
+ self.db._executeQueryCommand(getMoreCommand, command_options, function(err, result) {
+ var cbValue;
+
+ // Get more done
+ self.state = Cursor.OPEN;
+
+ if(err != null) {
+ return callback(utils.toError(err), null);
+ }
+
+ try {
+ var isDead = 1 === result.responseFlag && result.cursorId.isZero();
+
+ self.cursorId = result.cursorId;
+ self.totalNumberOfRecords += result.numberReturned;
+
+ // Determine if there's more documents to fetch
+ if(result.numberReturned > 0) {
+ if (self.limitValue > 0) {
+ var excessResult = self.totalNumberOfRecords - self.limitValue;
+
+ if (excessResult > 0) {
+ result.documents.splice(-1 * excessResult, excessResult);
+ }
+ }
+
+ // Reset the tries for awaitdata if we are using it
+ self.currentNumberOfRetries = self.numberOfRetries;
+ // Get the documents
+ for(var i = 0; i < result.documents.length; i++) {
+ self.items.push(result.documents[i]);
+ }
+
+ // Don's shift a document out as we need it for toArray
+ if(options.noReturn) {
+ cbValue = true;
+ } else {
+ cbValue = self.items.shift();
+ }
+ } else if(self.tailable && !isDead && self.awaitdata) {
+ // Excute the tailable cursor once more, will timeout after ~4 sec if awaitdata used
+ self.currentNumberOfRetries = self.currentNumberOfRetries - 1;
+ if(self.currentNumberOfRetries == 0) {
+ self.close(function() {
+ callback(new Error("tailable cursor timed out"), null);
+ });
+ } else {
+ getMore(self, callback);
+ }
+ } else if(self.tailable && !isDead) {
+ self.getMoreTimer = setTimeout(function() { getMore(self, callback); }, self.tailableRetryInterval);
+ } else {
+ self.close(function() {callback(null, null); });
+ }
+
+ result = null;
+ } catch(err) {
+ callback(utils.toError(err), null);
+ }
+ if (cbValue != null) callback(null, cbValue);
+ });
+
+ getMoreCommand = null;
+ } catch(err) {
+ // Get more done
+ self.state = Cursor.OPEN;
+
+ var handleClose = function() {
+ callback(utils.toError(err), null);
+ };
+
+ self.close(handleClose);
+ handleClose = null;
+ }
+}
+
+/**
+ * Gets a detailed information about how the query is performed on this cursor and how
+ * long it took the database to process it.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will always be null while the second parameter will be an object containing the details.
+ * @api public
+ */
+Cursor.prototype.explain = function(callback) {
+ var limit = (-1)*Math.abs(this.limitValue);
+
+ // Create a new cursor and fetch the plan
+ var cursor = new Cursor(this.db, this.collection, this.selector, this.fields, {
+ skip: this.skipValue
+ , limit:limit
+ , sort: this.sortValue
+ , hint: this.hint
+ , explain: true
+ , snapshot: this.snapshot
+ , timeout: this.timeout
+ , tailable: this.tailable
+ , batchSize: this.batchSizeValue
+ , slaveOk: this.slaveOk
+ , raw: this.raw
+ , read: this.read
+ , returnKey: this.returnKey
+ , maxScan: this.maxScan
+ , min: this.min
+ , max: this.max
+ , showDiskLoc: this.showDiskLoc
+ , comment: this.comment
+ , awaitdata: this.awaitdata
+ , numberOfRetries: this.numberOfRetries
+ , dbName: this.dbName
+ });
+
+ // Fetch the explaination document
+ cursor.nextObject(function(err, item) {
+ if(err != null) return callback(utils.toError(err), null);
+ // close the cursor
+ cursor.close(function(err, result) {
+ if(err != null) return callback(utils.toError(err), null);
+ callback(null, item);
+ });
+ });
+};
+
+/**
+ * Returns a Node ReadStream interface for this cursor.
+ *
+ * Options
+ * - **transform** {Function} function of type function(object) { return transformed }, allows for transformation of data before emitting.
+ *
+ * @return {CursorStream} returns a stream object.
+ * @api public
+ */
+Cursor.prototype.stream = function stream(options) {
+ return new CursorStream(this, options);
+}
+
+/**
+ * Close the cursor.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will always contain null while the second parameter will contain a reference to this cursor.
+ * @return {null}
+ * @api public
+ */
+Cursor.prototype.close = function(callback) {
+ var self = this
+ this.getMoreTimer && clearTimeout(this.getMoreTimer);
+ // Close the cursor if not needed
+ if(this.cursorId instanceof Long && this.cursorId.greaterThan(Long.fromInt(0))) {
+ try {
+ var command = new KillCursorCommand(this.db, [this.cursorId]);
+ // Added an empty callback to ensure we don't throw any null exceptions
+ this.db._executeQueryCommand(command, {read:self.read, raw:self.raw, connection:self.connection}, function() {});
+ } catch(err) {}
+ }
+
+ // Null out the connection
+ self.connection = null;
+ // Reset cursor id
+ this.cursorId = Long.fromInt(0);
+ // Set to closed status
+ this.state = Cursor.CLOSED;
+
+ if(callback) {
+ callback(null, self);
+ self.items = [];
+ }
+
+ return this;
+};
+
+/**
+ * Check if the cursor is closed or open.
+ *
+ * @return {Boolean} returns the state of the cursor.
+ * @api public
+ */
+Cursor.prototype.isClosed = function() {
+ return this.state == Cursor.CLOSED ? true : false;
+};
+
+/**
+ * Init state
+ *
+ * @classconstant INIT
+ **/
+Cursor.INIT = 0;
+
+/**
+ * Cursor open
+ *
+ * @classconstant OPEN
+ **/
+Cursor.OPEN = 1;
+
+/**
+ * Cursor closed
+ *
+ * @classconstant CLOSED
+ **/
+Cursor.CLOSED = 2;
+
+/**
+ * Cursor performing a get more
+ *
+ * @classconstant OPEN
+ **/
+Cursor.GET_MORE = 3;
+
+/**
+ * @ignore
+ * @api private
+ */
+exports.Cursor = Cursor;
diff --git a/node_modules/mongodb/lib/mongodb/cursorstream.js b/node_modules/mongodb/lib/mongodb/cursorstream.js
new file mode 100644
index 0000000..2752091
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/cursorstream.js
@@ -0,0 +1,164 @@
+var timers = require('timers');
+
+// Set processor, setImmediate if 0.10 otherwise nextTick
+var processor = timers.setImmediate ? timers.setImmediate : process.nextTick;
+
+/**
+ * Module dependecies.
+ */
+var Stream = require('stream').Stream;
+
+/**
+ * CursorStream
+ *
+ * Returns a stream interface for the **cursor**.
+ *
+ * Options
+ * - **transform** {Function} function of type function(object) { return transformed }, allows for transformation of data before emitting.
+ *
+ * Events
+ * - **data** {function(item) {}} the data event triggers when a document is ready.
+ * - **error** {function(err) {}} the error event triggers if an error happens.
+ * - **close** {function() {}} the end event triggers when there is no more documents available.
+ *
+ * @class Represents a CursorStream.
+ * @param {Cursor} cursor a cursor object that the stream wraps.
+ * @return {Stream}
+ */
+function CursorStream(cursor, options) {
+ if(!(this instanceof CursorStream)) return new CursorStream(cursor);
+ options = options ? options : {};
+
+ Stream.call(this);
+
+ this.readable = true;
+ this.paused = false;
+ this._cursor = cursor;
+ this._destroyed = null;
+ this.options = options;
+
+ // give time to hook up events
+ var self = this;
+ process.nextTick(function() {
+ self._init();
+ });
+}
+
+/**
+ * Inherit from Stream
+ * @ignore
+ * @api private
+ */
+CursorStream.prototype.__proto__ = Stream.prototype;
+
+/**
+ * Flag stating whether or not this stream is readable.
+ */
+CursorStream.prototype.readable;
+
+/**
+ * Flag stating whether or not this stream is paused.
+ */
+CursorStream.prototype.paused;
+
+/**
+ * Initialize the cursor.
+ * @ignore
+ * @api private
+ */
+CursorStream.prototype._init = function () {
+ if (this._destroyed) return;
+ this._next();
+}
+
+/**
+ * Pull the next document from the cursor.
+ * @ignore
+ * @api private
+ */
+CursorStream.prototype._next = function () {
+ if(this.paused || this._destroyed) return;
+
+ var self = this;
+ // Get the next object
+ processor(function() {
+ if(self.paused || self._destroyed) return;
+
+ self._cursor.nextObject(function (err, doc) {
+ self._onNextObject(err, doc);
+ });
+ });
+}
+
+/**
+ * Handle each document as its returned from the cursor.
+ * @ignore
+ * @api private
+ */
+CursorStream.prototype._onNextObject = function (err, doc) {
+ if(err) return this.destroy(err);
+
+ // when doc is null we hit the end of the cursor
+ if(!doc && (this._cursor.state == 1 || this._cursor.state == 2)) {
+ this.emit('end')
+ return this.destroy();
+ } else if(doc) {
+ var data = typeof this.options.transform == 'function' ? this.options.transform(doc) : doc;
+ this.emit('data', data);
+ this._next();
+ }
+}
+
+/**
+ * Pauses the stream.
+ *
+ * @api public
+ */
+CursorStream.prototype.pause = function () {
+ this.paused = true;
+}
+
+/**
+ * Resumes the stream.
+ *
+ * @api public
+ */
+CursorStream.prototype.resume = function () {
+ var self = this;
+
+ // Don't do anything if we are not paused
+ if(!this.paused) return;
+ if(!this._cursor.state == 3) return;
+
+ process.nextTick(function() {
+ self.paused = false;
+ // Only trigger more fetching if the cursor is open
+ self._next();
+ })
+}
+
+/**
+ * Destroys the stream, closing the underlying
+ * cursor. No more events will be emitted.
+ *
+ * @api public
+ */
+CursorStream.prototype.destroy = function (err) {
+ if (this._destroyed) return;
+ this._destroyed = true;
+ this.readable = false;
+
+ this._cursor.close();
+
+ if(err) {
+ this.emit('error', err);
+ }
+
+ this.emit('close');
+}
+
+// TODO - maybe implement the raw option to pass binary?
+//CursorStream.prototype.setEncoding = function () {
+//}
+
+module.exports = exports = CursorStream;
diff --git a/node_modules/mongodb/lib/mongodb/db.js b/node_modules/mongodb/lib/mongodb/db.js
new file mode 100644
index 0000000..04620f3
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/db.js
@@ -0,0 +1,1932 @@
+/**
+ * Module dependencies.
+ * @ignore
+ */
+var QueryCommand = require('./commands/query_command').QueryCommand
+ , DbCommand = require('./commands/db_command').DbCommand
+ , MongoReply = require('./responses/mongo_reply').MongoReply
+ , Admin = require('./admin').Admin
+ , Collection = require('./collection').Collection
+ , Server = require('./connection/server').Server
+ , ReplSet = require('./connection/repl_set/repl_set').ReplSet
+ , ReadPreference = require('./connection/read_preference').ReadPreference
+ , Mongos = require('./connection/mongos').Mongos
+ , Cursor = require('./cursor').Cursor
+ , EventEmitter = require('events').EventEmitter
+ , inherits = require('util').inherits
+ , crypto = require('crypto')
+ , timers = require('timers')
+ , utils = require('./utils')
+ , mongodb_cr_authenticate = require('./auth/mongodb_cr.js').authenticate
+ , mongodb_gssapi_authenticate = require('./auth/mongodb_gssapi.js').authenticate
+ , mongodb_sspi_authenticate = require('./auth/mongodb_sspi.js').authenticate;
+
+var hasKerberos = false;
+// Check if we have a the kerberos library
+try {
+ require('kerberos');
+ hasKerberos = true;
+} catch(err) {}
+
+// Set processor, setImmediate if 0.10 otherwise nextTick
+var processor = timers.setImmediate ? timers.setImmediate : process.nextTick;
+
+/**
+ * Create a new Db instance.
+ *
+ * Options
+ * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * - **native_parser** {Boolean, default:false}, use c++ bson parser.
+ * - **forceServerObjectId** {Boolean, default:false}, force server to create _id fields instead of client.
+ * - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation.
+ * - **serializeFunctions** {Boolean, default:false}, serialize functions.
+ * - **raw** {Boolean, default:false}, peform operations using raw bson buffers.
+ * - **recordQueryStats** {Boolean, default:false}, record query statistics during execution.
+ * - **retryMiliSeconds** {Number, default:5000}, number of miliseconds between retries.
+ * - **numberOfRetries** {Number, default:5}, number of retries off connection.
+ * - **logger** {Object, default:null}, an object representing a logger that you want to use, needs to support functions debug, log, error **({error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}})**.
+ * - **slaveOk** {Number, default:null}, force setting of SlaveOk flag on queries (only use when explicitly connecting to a secondary server).
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @class Represents a Db
+ * @param {String} databaseName name of the database.
+ * @param {Object} serverConfig server config object.
+ * @param {Object} [options] additional options for the collection.
+ */
+function Db(databaseName, serverConfig, options) {
+ if(!(this instanceof Db)) return new Db(databaseName, serverConfig, options);
+ EventEmitter.call(this);
+
+ var self = this;
+ this.databaseName = databaseName;
+ this.serverConfig = serverConfig;
+ this.options = options == null ? {} : options;
+ // State to check against if the user force closed db
+ this._applicationClosed = false;
+ // Fetch the override flag if any
+ var overrideUsedFlag = this.options['override_used_flag'] == null ? false : this.options['override_used_flag'];
+
+ // Verify that nobody is using this config
+ if(!overrideUsedFlag && this.serverConfig != null && typeof this.serverConfig == 'object' && this.serverConfig._isUsed && this.serverConfig._isUsed()) {
+ throw new Error("A Server or ReplSet instance cannot be shared across multiple Db instances");
+ } else if(!overrideUsedFlag && typeof this.serverConfig == 'object'){
+ // Set being used
+ this.serverConfig._used = true;
+ }
+
+ // Allow slaveOk override
+ this.slaveOk = this.options["slave_ok"] == null ? false : this.options["slave_ok"];
+ this.slaveOk = this.options["slaveOk"] == null ? this.slaveOk : this.options["slaveOk"];
+
+ // Ensure we have a valid db name
+ validateDatabaseName(databaseName);
+
+ // Contains all the connections for the db
+ try {
+ this.native_parser = this.options.native_parser;
+ // The bson lib
+ var bsonLib = this.bsonLib = this.options.native_parser ? require('bson').BSONNative : require('bson').BSONPure;
+ // Fetch the serializer object
+ var BSON = bsonLib.BSON;
+ // Create a new instance
+ this.bson = new BSON([bsonLib.Long, bsonLib.ObjectID, bsonLib.Binary, bsonLib.Code, bsonLib.DBRef, bsonLib.Symbol, bsonLib.Double, bsonLib.Timestamp, bsonLib.MaxKey, bsonLib.MinKey]);
+ // Backward compatibility to access types
+ this.bson_deserializer = bsonLib;
+ this.bson_serializer = bsonLib;
+ } catch (err) {
+ // If we tried to instantiate the native driver
+ var msg = "Native bson parser not compiled, please compile "
+ + "or avoid using native_parser=true";
+ throw Error(msg);
+ }
+
+ // Internal state of the server
+ this._state = 'disconnected';
+
+ this.pkFactory = this.options.pk == null ? bsonLib.ObjectID : this.options.pk;
+ this.forceServerObjectId = this.options.forceServerObjectId != null ? this.options.forceServerObjectId : false;
+
+ // Added safe
+ this.safe = this.options.safe == null ? false : this.options.safe;
+
+ // If we have not specified a "safe mode" we just print a warning to the console
+ if(this.options.safe == null && this.options.w == null && this.options.journal == null && this.options.fsync == null) {
+ console.log("========================================================================================");
+ console.log("= Please ensure that you set the default write concern for the database by setting =");
+ console.log("= one of the options =");
+ console.log("= =");
+ console.log("= w: (value of > -1 or the string 'majority'), where < 1 means =");
+ console.log("= no write acknowlegement =");
+ console.log("= journal: true/false, wait for flush to journal before acknowlegement =");
+ console.log("= fsync: true/false, wait for flush to file system before acknowlegement =");
+ console.log("= =");
+ console.log("= For backward compatibility safe is still supported and =");
+ console.log("= allows values of [true | false | {j:true} | {w:n, wtimeout:n} | {fsync:true}] =");
+ console.log("= the default value is false which means the driver receives does not =");
+ console.log("= return the information of the success/error of the insert/update/remove =");
+ console.log("= =");
+ console.log("= ex: new Db(new Server('localhost', 27017), {safe:false}) =");
+ console.log("= =");
+ console.log("= http://www.mongodb.org/display/DOCS/getLastError+Command =");
+ console.log("= =");
+ console.log("= The default of no acknowlegement will change in the very near future =");
+ console.log("= =");
+ console.log("= This message will disappear when the default safe is set on the driver Db =");
+ console.log("========================================================================================");
+ }
+
+ // Internal states variables
+ this.notReplied ={};
+ this.isInitializing = true;
+ this.openCalled = false;
+
+ // Command queue, keeps a list of incoming commands that need to be executed once the connection is up
+ this.commands = [];
+
+ // Set up logger
+ this.logger = this.options.logger != null
+ && (typeof this.options.logger.debug == 'function')
+ && (typeof this.options.logger.error == 'function')
+ && (typeof this.options.logger.log == 'function')
+ ? this.options.logger : {error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}};
+
+ // Associate the logger with the server config
+ this.serverConfig.logger = this.logger;
+ if(this.serverConfig.strategyInstance) this.serverConfig.strategyInstance.logger = this.logger;
+ this.tag = new Date().getTime();
+ // Just keeps list of events we allow
+ this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[]};
+
+ // Controls serialization options
+ this.serializeFunctions = this.options.serializeFunctions != null ? this.options.serializeFunctions : false;
+
+ // Raw mode
+ this.raw = this.options.raw != null ? this.options.raw : false;
+
+ // Record query stats
+ this.recordQueryStats = this.options.recordQueryStats != null ? this.options.recordQueryStats : false;
+
+ // If we have server stats let's make sure the driver objects have it enabled
+ if(this.recordQueryStats == true) {
+ this.serverConfig.enableRecordQueryStats(true);
+ }
+
+ // Retry information
+ this.retryMiliSeconds = this.options.retryMiliSeconds != null ? this.options.retryMiliSeconds : 1000;
+ this.numberOfRetries = this.options.numberOfRetries != null ? this.options.numberOfRetries : 60;
+
+ // Set default read preference if any
+ this.readPreference = this.options.readPreference;
+
+ // Set read preference on serverConfig if none is set
+ // but the db one was
+ if(this.serverConfig.options.readPreference == null
+ && this.readPreference != null) {
+ this.serverConfig.setReadPreference(this.readPreference);
+ }
+
+ // Ensure we keep a reference to this db
+ this.serverConfig._dbStore.add(this);
+};
+
+/**
+ * @ignore
+ */
+function validateDatabaseName(databaseName) {
+ if(typeof databaseName !== 'string') throw new Error("database name must be a string");
+ if(databaseName.length === 0) throw new Error("database name cannot be the empty string");
+
+ var invalidChars = [" ", ".", "$", "/", "\\"];
+ for(var i = 0; i < invalidChars.length; i++) {
+ if(databaseName.indexOf(invalidChars[i]) != -1) throw new Error("database names cannot contain the character '" + invalidChars[i] + "'");
+ }
+}
+
+/**
+ * @ignore
+ */
+inherits(Db, EventEmitter);
+
+/**
+ * Initialize the database connection.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the index information or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.open = function(callback) {
+ var self = this;
+
+ // Check that the user has not called this twice
+ if(this.openCalled) {
+ // Close db
+ this.close();
+ // Throw error
+ throw new Error("db object already connecting, open cannot be called multiple times");
+ }
+
+ // If we have a specified read preference
+ if(this.readPreference != null) this.serverConfig.setReadPreference(this.readPreference);
+
+ // Set that db has been opened
+ this.openCalled = true;
+
+ // Set the status of the server
+ self._state = 'connecting';
+
+ // Set up connections
+ if(self.serverConfig instanceof Server || self.serverConfig instanceof ReplSet || self.serverConfig instanceof Mongos) {
+ // Ensure we have the original options passed in for the server config
+ var connect_options = {};
+ for(var name in self.serverConfig.options) {
+ connect_options[name] = self.serverConfig.options[name]
+ }
+ connect_options.firstCall = true;
+
+ // Attempt to connect
+ self.serverConfig.connect(self, connect_options, function(err, result) {
+ if(err != null) {
+ // Set that db has been closed
+ self.openCalled = false;
+ // Return error from connection
+ return callback(err, null);
+ }
+ // Set the status of the server
+ self._state = 'connected';
+ // If we have queued up commands execute a command to trigger replays
+ if(self.commands.length > 0) _execute_queued_command(self);
+ // Callback
+ return callback(null, self);
+ });
+ } else {
+ return callback(Error("Server parameter must be of type Server, ReplSet or Mongos"), null);
+ }
+};
+
+/**
+ * Create a new Db instance sharing the current socket connections.
+ *
+ * @param {String} dbName the name of the database we want to use.
+ * @return {Db} a db instance using the new database.
+ * @api public
+ */
+Db.prototype.db = function(dbName) {
+ // Copy the options and add out internal override of the not shared flag
+ var options = {};
+ for(var key in this.options) {
+ options[key] = this.options[key];
+ }
+
+ // Add override flag
+ options['override_used_flag'] = true;
+ // Create a new db instance
+ var newDbInstance = new Db(dbName, this.serverConfig, options);
+ // Add the instance to the list of approved db instances
+ var allServerInstances = this.serverConfig.allServerInstances();
+ // Add ourselves to all server callback instances
+ for(var i = 0; i < allServerInstances.length; i++) {
+ // var server = allServerInstances[i];
+ // server.dbInstances.push(newDbInstance);
+ this.serverConfig._dbStore.add(newDbInstance);
+ }
+ // Return new db object
+ return newDbInstance;
+}
+
+/**
+ * Close the current db connection, including all the child db instances. Emits close event if no callback is provided.
+ *
+ * @param {Boolean} [forceClose] connection can never be reused.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.close = function(forceClose, callback) {
+ var self = this;
+ // Ensure we force close all connections
+ this._applicationClosed = false;
+
+ if(typeof forceClose == 'function') {
+ callback = forceClose;
+ } else if(typeof forceClose == 'boolean') {
+ this._applicationClosed = forceClose;
+ }
+
+ this.serverConfig.close(function(err, result) {
+ // You can reuse the db as everything is shut down
+ self.openCalled = false;
+ // If we have a callback call it
+ if(callback) callback(err, result);
+ });
+};
+
+/**
+ * Access the Admin database
+ *
+ * @param {Function} [callback] returns the results.
+ * @return {Admin} the admin db object.
+ * @api public
+ */
+Db.prototype.admin = function(callback) {
+ if(callback == null) return new Admin(this);
+ callback(null, new Admin(this));
+};
+
+/**
+ * Returns a cursor to all the collection information.
+ *
+ * @param {String} [collectionName] the collection name we wish to retrieve the information from.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the options or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.collectionsInfo = function(collectionName, callback) {
+ if(callback == null && typeof collectionName == 'function') { callback = collectionName; collectionName = null; }
+ // Create selector
+ var selector = {};
+ // If we are limiting the access to a specific collection name
+ if(collectionName != null) selector.name = this.databaseName + "." + collectionName;
+
+ // Return Cursor
+ // callback for backward compatibility
+ if(callback) {
+ callback(null, new Cursor(this, new Collection(this, DbCommand.SYSTEM_NAMESPACE_COLLECTION), selector));
+ } else {
+ return new Cursor(this, new Collection(this, DbCommand.SYSTEM_NAMESPACE_COLLECTION), selector);
+ }
+};
+
+/**
+ * Get the list of all collection names for the specified db
+ *
+ * Options
+ * - **namesOnly** {String, default:false}, Return only the full collection namespace.
+ *
+ * @param {String} [collectionName] the collection name we wish to filter by.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the collection names or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.collectionNames = function(collectionName, options, callback) {
+ var self = this;
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ collectionName = args.length ? args.shift() : null;
+ options = args.length ? args.shift() || {} : {};
+
+ // Ensure no breaking behavior
+ if(collectionName != null && typeof collectionName == 'object') {
+ options = collectionName;
+ collectionName = null;
+ }
+
+ // Let's make our own callback to reuse the existing collections info method
+ self.collectionsInfo(collectionName, function(err, cursor) {
+ if(err != null) return callback(err, null);
+
+ cursor.toArray(function(err, documents) {
+ if(err != null) return callback(err, null);
+
+ // List of result documents that have been filtered
+ var filtered_documents = documents.filter(function(document) {
+ return !(document.name.indexOf(self.databaseName) == -1 || document.name.indexOf('$') != -1);
+ });
+
+ // If we are returning only the names
+ if(options.namesOnly) {
+ filtered_documents = filtered_documents.map(function(document) { return document.name });
+ }
+
+ // Return filtered items
+ callback(null, filtered_documents);
+ });
+ });
+};
+
+/**
+ * Fetch a specific collection (containing the actual collection information). If the application does not use strict mode you can
+ * can use it without a callback in the following way. var collection = db.collection('mycollection');
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **serializeFunctions** {Boolean, default:false}, serialize functions on the document.
+ * - **raw** {Boolean, default:false}, perform all operations using raw bson objects.
+ * - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation.
+ * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * - **strict**, (Boolean, default:false) throws an error if the collection does not exist
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {String} collectionName the collection name we wish to access.
+ * @param {Object} [options] returns option results.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the collection or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.collection = function(collectionName, options, callback) {
+ var self = this;
+ if(typeof options === "function") { callback = options; options = {}; }
+ // Execute safe
+
+ if(options && (options.strict)) {
+ self.collectionNames(collectionName, function(err, collections) {
+ if(err != null) return callback(err, null);
+
+ if(collections.length == 0) {
+ return callback(new Error("Collection " + collectionName + " does not exist. Currently in safe mode."), null);
+ } else {
+ try {
+ var collection = new Collection(self, collectionName, self.pkFactory, options);
+ } catch(err) {
+ return callback(err, null);
+ }
+ return callback(null, collection);
+ }
+ });
+ } else {
+ try {
+ var collection = new Collection(self, collectionName, self.pkFactory, options);
+ } catch(err) {
+ if(callback == null) {
+ throw err;
+ } else {
+ return callback(err, null);
+ }
+ }
+
+ // If we have no callback return collection object
+ return callback == null ? collection : callback(null, collection);
+ }
+};
+
+/**
+ * Fetch all collections for the current db.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the collections or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.collections = function(callback) {
+ var self = this;
+ // Let's get the collection names
+ self.collectionNames(function(err, documents) {
+ if(err != null) return callback(err, null);
+ var collections = [];
+ documents.forEach(function(document) {
+ collections.push(new Collection(self, document.name.replace(self.databaseName + ".", ''), self.pkFactory));
+ });
+ // Return the collection objects
+ callback(null, collections);
+ });
+};
+
+/**
+ * Evaluate javascript on the server
+ *
+ * Options
+ * - **nolock** {Boolean, default:false}, Tell MongoDB not to block on the evaulation of the javascript.
+ *
+ * @param {Code} code javascript to execute on server.
+ * @param {Object|Array} [parameters] the parameters for the call.
+ * @param {Object} [options] the options
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from eval or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.eval = function(code, parameters, options, callback) {
+ // Unpack calls
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ parameters = args.length ? args.shift() : parameters;
+ options = args.length ? args.shift() || {} : {};
+
+ var finalCode = code;
+ var finalParameters = [];
+ // If not a code object translate to one
+ if(!(finalCode instanceof this.bsonLib.Code)) {
+ finalCode = new this.bsonLib.Code(finalCode);
+ }
+
+ // Ensure the parameters are correct
+ if(parameters != null && parameters.constructor != Array && typeof parameters !== 'function') {
+ finalParameters = [parameters];
+ } else if(parameters != null && parameters.constructor == Array && typeof parameters !== 'function') {
+ finalParameters = parameters;
+ }
+
+ // Create execution selector
+ var selector = {'$eval':finalCode, 'args':finalParameters};
+ // Check if the nolock parameter is passed in
+ if(options['nolock']) {
+ selector['nolock'] = options['nolock'];
+ }
+
+ // Set primary read preference
+ options.readPreference = ReadPreference.PRIMARY;
+
+ // Execute the eval
+ this.collection(DbCommand.SYSTEM_COMMAND_COLLECTION).findOne(selector, options, function(err, result) {
+ if(err) return callback(err);
+
+ if(result && result.ok == 1) {
+ callback(null, result.retval);
+ } else if(result) {
+ callback(new Error("eval failed: " + result.errmsg), null); return;
+ } else {
+ callback(err, result);
+ }
+ });
+};
+
+/**
+ * Dereference a dbref, against a db
+ *
+ * @param {DBRef} dbRef db reference object we wish to resolve.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from dereference or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.dereference = function(dbRef, callback) {
+ var db = this;
+ // If we have a db reference then let's get the db first
+ if(dbRef.db != null) db = this.db(dbRef.db);
+ // Fetch the collection and find the reference
+ var collection = db.collection(dbRef.namespace);
+ collection.findOne({'_id':dbRef.oid}, function(err, result) {
+ callback(err, result);
+ });
+};
+
+/**
+ * Logout user from server, fire off on all connections and remove all auth info
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from logout or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.logout = function(options, callback) {
+ var self = this;
+ // Unpack calls
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+
+ // Number of connections we need to logout from
+ var numberOfConnections = this.serverConfig.allRawConnections().length;
+
+ // Let's generate the logout command object
+ var logoutCommand = DbCommand.logoutCommand(self, {logout:1}, options);
+ self._executeQueryCommand(logoutCommand, {onAll:true}, function(err, result) {
+ // Count down
+ numberOfConnections = numberOfConnections - 1;
+ // Work around the case where the number of connections are 0
+ if(numberOfConnections <= 0 && typeof callback == 'function') {
+ var internalCallback = callback;
+ callback = null;
+
+ // Remove the db from auths
+ self.serverConfig.auth.remove(self.databaseName);
+
+ // Handle any errors
+ if(err == null && result.documents[0].ok == 1) {
+ internalCallback(null, true);
+ } else {
+ err != null ? internalCallback(err, false) : internalCallback(new Error(result.documents[0].errmsg), false);
+ }
+ }
+ });
+}
+
+/**
+ * Authenticate a user against the server.
+ * authMechanism
+ * Options
+ * - **authSource** {String}, The database that the credentials are for,
+ * different from the name of the current DB, for example admin
+ * - **authMechanism** {String, default:MONGODB-CR}, The authentication mechanism to use, GSSAPI or MONGODB-CR
+ *
+ * @param {String} username username.
+ * @param {String} password password.
+ * @param {Object} [options] the options
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from authentication or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.authenticate = function(username, password, options, callback) {
+ var self = this;
+
+ if(typeof callback === 'undefined') {
+ callback = options;
+ options = {};
+ }
+
+ // Set default mechanism
+ if(!options.authMechanism) {
+ options.authMechanism = 'MONGODB-CR';
+ } else if(options.authMechanism != 'GSSAPI' && options.authMechanism != 'MONGODB-CR') {
+ return callback(new Error("only GSSAPI or MONGODB-CR is supported by authMechanism"));
+ }
+
+ // the default db to authenticate against is 'this'
+ // if authententicate is called from a retry context, it may be another one, like admin
+ var authdb = options.authdb ? options.authdb : self.databaseName;
+ authdb = options.authSource ? options.authSource : authdb;
+
+ // Callback
+ var _callback = function(err, result) {
+ if(self.listeners("authenticated").length > 9) {
+ self.emit("authenticated", err, result);
+ }
+
+ // Return to caller
+ callback(err, result);
+ }
+
+ // If classic auth delegate to auth command
+ if(options.authMechanism == 'MONGODB-CR') {
+ mongodb_cr_authenticate(self, username, password, authdb, options, _callback);
+ } else if(options.authMechanism == 'GSSAPI') {
+ //
+ // Kerberos library is not installed, throw and error
+ if(hasKerberos == false) {
+ console.log("========================================================================================");
+ console.log("= Please make sure that you install the Kerberos library to use GSSAPI =");
+ console.log("= =");
+ console.log("= npm install -g kerberos =");
+ console.log("= =");
+ console.log("= The Kerberos package is not installed by default for simplicities sake =");
+ console.log("= and needs to be global install =");
+ console.log("========================================================================================");
+ throw new Error("Kerberos library not installed");
+ }
+
+ if(process.platform == 'win32') {
+ mongodb_sspi_authenticate(self, username, password, authdb, options, _callback);
+ } else {
+ // We have the kerberos library, execute auth process
+ mongodb_gssapi_authenticate(self, username, password, authdb, options, _callback);
+ }
+ }
+};
+
+/**
+ * Add a user to the database.
+ *
+ * Options
+ * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {String} username username.
+ * @param {String} password password.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from addUser or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.addUser = function(username, password, options, callback) {
+ var self = this;
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+
+ // Get the error options
+ var errorOptions = _getWriteConcern(this, options, callback);
+ errorOptions.w = errorOptions.w == null ? 1 : errorOptions.w;
+ // Use node md5 generator
+ var md5 = crypto.createHash('md5');
+ // Generate keys used for authentication
+ md5.update(username + ":mongo:" + password);
+ var userPassword = md5.digest('hex');
+ // Fetch a user collection
+ var collection = this.collection(DbCommand.SYSTEM_USER_COLLECTION);
+ // Check if we are inserting the first user
+ collection.count({}, function(err, count) {
+ // We got an error (f.ex not authorized)
+ if(err != null) return callback(err, null);
+ // Check if the user exists and update i
+ collection.find({user: username}, {dbName: options['dbName']}).toArray(function(err, documents) {
+ // We got an error (f.ex not authorized)
+ if(err != null) return callback(err, null);
+ // Add command keys
+ var commandOptions = errorOptions;
+ commandOptions.dbName = options['dbName'];
+ commandOptions.upsert = true;
+
+ // We have a user, let's update the password or upsert if not
+ collection.update({user: username},{$set: {user: username, pwd: userPassword}}, commandOptions, function(err, results) {
+ if(count == 0 && err) {
+ callback(null, [{user:username, pwd:userPassword}]);
+ } else if(err) {
+ callback(err, null)
+ } else {
+ callback(null, [{user:username, pwd:userPassword}]);
+ }
+ });
+ });
+ });
+};
+
+/**
+ * Remove a user from a database
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {String} username username.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from removeUser or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.removeUser = function(username, options, callback) {
+ var self = this;
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+
+ // Figure out the safe mode settings
+ var safe = self.safe != null && self.safe == false ? {w: 1} : self.safe;
+ // Override with options passed in if applicable
+ safe = options != null && options['safe'] != null ? options['safe'] : safe;
+ // Ensure it's at least set to safe
+ safe = safe == null ? {w: 1} : safe;
+
+ // Fetch a user collection
+ var collection = this.collection(DbCommand.SYSTEM_USER_COLLECTION);
+ collection.findOne({user: username}, {dbName: options['dbName']}, function(err, user) {
+ if(user != null) {
+ // Add command keys
+ var commandOptions = safe;
+ commandOptions.dbName = options['dbName'];
+
+ collection.remove({user: username}, commandOptions, function(err, result) {
+ callback(err, true);
+ });
+ } else {
+ callback(err, false);
+ }
+ });
+};
+
+/**
+ * Creates a collection on a server pre-allocating space, need to create f.ex capped collections.
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **serializeFunctions** {Boolean, default:false}, serialize functions on the document.
+ * - **raw** {Boolean, default:false}, perform all operations using raw bson objects.
+ * - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation.
+ * - **capped** {Boolean, default:false}, create a capped collection.
+ * - **size** {Number}, the size of the capped collection in bytes.
+ * - **max** {Number}, the maximum number of documents in the capped collection.
+ * - **autoIndexId** {Boolean, default:true}, create an index on the _id field of the document, True by default on MongoDB 2.2 or higher off for version < 2.2.
+ * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * - **strict**, (Boolean, default:false) throws an error if collection already exists
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {String} collectionName the collection name we wish to access.
+ * @param {Object} [options] returns option results.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from createCollection or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.createCollection = function(collectionName, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ options = args.length ? args.shift() : null;
+ var self = this;
+
+ // Figure out the safe mode settings
+ var safe = self.safe != null && self.safe == false ? {w: 1} : self.safe;
+ // Override with options passed in if applicable
+ safe = options != null && options['safe'] != null ? options['safe'] : safe;
+ // Ensure it's at least set to safe
+ safe = safe == null ? {w: 1} : safe;
+
+ // Check if we have the name
+ this.collectionNames(collectionName, function(err, collections) {
+ if(err != null) return callback(err, null);
+
+ var found = false;
+ collections.forEach(function(collection) {
+ if(collection.name == self.databaseName + "." + collectionName) found = true;
+ });
+
+ // If the collection exists either throw an exception (if db in safe mode) or return the existing collection
+ if(found && options && options.strict) {
+ return callback(new Error("Collection " + collectionName + " already exists. Currently in safe mode."), null);
+ } else if(found){
+ try {
+ var collection = new Collection(self, collectionName, self.pkFactory, options);
+ } catch(err) {
+ return callback(err, null);
+ }
+ return callback(null, collection);
+ }
+
+ // Create a new collection and return it
+ self._executeQueryCommand(DbCommand.createCreateCollectionCommand(self, collectionName, options), {read:false, safe:safe}, function(err, result) {
+ var document = result.documents[0];
+ // If we have no error let's return the collection
+ if(err == null && document.ok == 1) {
+ try {
+ var collection = new Collection(self, collectionName, self.pkFactory, options);
+ } catch(err) {
+ return callback(err, null);
+ }
+ return callback(null, collection);
+ } else {
+ if (null == err) err = utils.toError(document);
+ callback(err, null);
+ }
+ });
+ });
+};
+
+/**
+ * Execute a command hash against MongoDB. This lets you acess any commands not available through the api on the server.
+ *
+ * @param {Object} selector the command hash to send to the server, ex: {ping:1}.
+ * @param {Function} callback this will be called after executing this method. The command always return the whole result of the command as the second parameter.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.command = function(selector, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+
+ // Set up the options
+ var cursor = new Cursor(this
+ , new Collection(this, DbCommand.SYSTEM_COMMAND_COLLECTION), selector, {}, {
+ limit: -1, timeout: QueryCommand.OPTS_NO_CURSOR_TIMEOUT, dbName: options['dbName']
+ });
+
+ // Set read preference if we set one
+ var readPreference = options['readPreference'] ? options['readPreference'] : false;
+
+ // Ensure only commands who support read Prefrences are exeuted otherwise override and use Primary
+ if(readPreference != false) {
+ if(selector['group'] || selector['aggregate'] || selector['collStats'] || selector['dbStats']
+ || selector['count'] || selector['distinct'] || selector['geoNear'] || selector['geoSearch'] || selector['geoWalk']
+ || (selector['mapreduce'] && selector.out == 'inline')) {
+ // Set the read preference
+ cursor.setReadPreference(readPreference);
+ } else {
+ cursor.setReadPreference(ReadPreference.PRIMARY);
+ }
+ }
+
+ // Return the next object
+ cursor.nextObject(callback);
+};
+
+/**
+ * Drop a collection from the database, removing it permanently. New accesses will create a new collection.
+ *
+ * @param {String} collectionName the name of the collection we wish to drop.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from dropCollection or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.dropCollection = function(collectionName, callback) {
+ var self = this;
+ callback || (callback = function(){});
+
+ // Drop the collection
+ this._executeQueryCommand(DbCommand.createDropCollectionCommand(this, collectionName), function(err, result) {
+ if(err == null && result.documents[0].ok == 1) {
+ return callback(null, true);
+ }
+
+ if(null == err) err = utils.toError(result.documents[0]);
+ callback(err, null);
+ });
+};
+
+/**
+ * Rename a collection.
+ *
+ * Options
+ * - **dropTarget** {Boolean, default:false}, drop the target name collection if it previously exists.
+ *
+ * @param {String} fromCollection the name of the current collection we wish to rename.
+ * @param {String} toCollection the new name of the collection.
+ * @param {Object} [options] returns option results.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from renameCollection or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.renameCollection = function(fromCollection, toCollection, options, callback) {
+ var self = this;
+
+ if(typeof options == 'function') {
+ callback = options;
+ options = {}
+ }
+
+ callback || (callback = function(){});
+ // Execute the command, return the new renamed collection if successful
+ this._executeQueryCommand(DbCommand.createRenameCollectionCommand(this, fromCollection, toCollection, options), function(err, result) {
+ if(err == null && result.documents[0].ok == 1) {
+ return callback(null, new Collection(self, toCollection, self.pkFactory));
+ }
+
+ if(null == err) err = utils.toError(result.documents[0]);
+ callback(err, null);
+ });
+};
+
+/**
+ * Return last error message for the given connection, note options can be combined.
+ *
+ * Options
+ * - **fsync** {Boolean, default:false}, option forces the database to fsync all files before returning.
+ * - **j** {Boolean, default:false}, awaits the journal commit before returning, > MongoDB 2.0.
+ * - **w** {Number}, until a write operation has been replicated to N servers.
+ * - **wtimeout** {Number}, number of miliseconds to wait before timing out.
+ *
+ * Connection Options
+ * - **connection** {Connection}, fire the getLastError down a specific connection.
+ *
+ * @param {Object} [options] returns option results.
+ * @param {Object} [connectionOptions] returns option results.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from lastError or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.lastError = function(options, connectionOptions, callback) {
+ // Unpack calls
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+ connectionOptions = args.length ? args.shift() || {} : {};
+
+ this._executeQueryCommand(DbCommand.createGetLastErrorCommand(options, this), connectionOptions, function(err, error) {
+ callback(err, error && error.documents);
+ });
+};
+
+/**
+ * Legacy method calls.
+ *
+ * @ignore
+ * @api private
+ */
+Db.prototype.error = Db.prototype.lastError;
+Db.prototype.lastStatus = Db.prototype.lastError;
+
+/**
+ * Return all errors up to the last time db reset_error_history was called.
+ *
+ * Options
+ * - **connection** {Connection}, fire the getLastError down a specific connection.
+ *
+ * @param {Object} [options] returns option results.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from previousErrors or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.previousErrors = function(options, callback) {
+ // Unpack calls
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+
+ this._executeQueryCommand(DbCommand.createGetPreviousErrorsCommand(this), options, function(err, error) {
+ callback(err, error.documents);
+ });
+};
+
+/**
+ * Runs a command on the database.
+ * @ignore
+ * @api private
+ */
+Db.prototype.executeDbCommand = function(command_hash, options, callback) {
+ if(callback == null) { callback = options; options = {}; }
+ this._executeQueryCommand(DbCommand.createDbSlaveOkCommand(this, command_hash, options), options, callback);
+};
+
+/**
+ * Runs a command on the database as admin.
+ * @ignore
+ * @api private
+ */
+Db.prototype.executeDbAdminCommand = function(command_hash, options, callback) {
+ if(callback == null) { callback = options; options = {}; }
+ this._executeQueryCommand(DbCommand.createAdminDbCommand(this, command_hash), options, callback);
+};
+
+/**
+ * Resets the error history of the mongo instance.
+ *
+ * Options
+ * - **connection** {Connection}, fire the getLastError down a specific connection.
+ *
+ * @param {Object} [options] returns option results.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from resetErrorHistory or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.resetErrorHistory = function(options, callback) {
+ // Unpack calls
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+
+ this._executeQueryCommand(DbCommand.createResetErrorHistoryCommand(this), options, function(err, error) {
+ callback(err, error.documents);
+ });
+};
+
+/**
+ * Creates an index on the collection.
+ *
+ * Options
+* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **unique** {Boolean, default:false}, creates an unique index.
+ * - **sparse** {Boolean, default:false}, creates a sparse index.
+ * - **background** {Boolean, default:false}, creates the index in the background, yielding whenever possible.
+ * - **dropDups** {Boolean, default:false}, a unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
+ * - **min** {Number}, for geospatial indexes set the lower bound for the co-ordinates.
+ * - **max** {Number}, for geospatial indexes set the high bound for the co-ordinates.
+ * - **v** {Number}, specify the format version of the indexes.
+ * - **expireAfterSeconds** {Number}, allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
+ * - **name** {String}, override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ *
+ * @param {String} collectionName name of the collection to create the index on.
+ * @param {Object} fieldOrSpec fieldOrSpec that defines the index.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from createIndex or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.createIndex = function(collectionName, fieldOrSpec, options, callback) {
+ var self = this;
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+ options = typeof callback === 'function' ? options : callback;
+ options = options == null ? {} : options;
+
+ // Get the error options
+ var errorOptions = _getWriteConcern(this, options, callback);
+ // Create command
+ var command = DbCommand.createCreateIndexCommand(this, collectionName, fieldOrSpec, options);
+ // Default command options
+ var commandOptions = {};
+
+ // If we have error conditions set handle them
+ if(_hasWriteConcern(errorOptions) && typeof callback == 'function') {
+ // Insert options
+ commandOptions['read'] = false;
+ // If we have safe set set async to false
+ if(errorOptions == null) commandOptions['async'] = true;
+
+ // Set safe option
+ commandOptions['safe'] = errorOptions;
+ // If we have an error option
+ if(typeof errorOptions == 'object') {
+ var keys = Object.keys(errorOptions);
+ for(var i = 0; i < keys.length; i++) {
+ commandOptions[keys[i]] = errorOptions[keys[i]];
+ }
+ }
+
+ // Execute insert command
+ this._executeInsertCommand(command, commandOptions, function(err, result) {
+ if(err != null) return callback(err, null);
+
+ result = result && result.documents;
+ if (result[0].err) {
+ callback(utils.toError(result[0]));
+ } else {
+ callback(null, command.documents[0].name);
+ }
+ });
+ } else if(_hasWriteConcern(errorOptions) && callback == null) {
+ throw new Error("Cannot use a writeConcern without a provided callback");
+ } else {
+ // Execute insert command
+ var result = this._executeInsertCommand(command, commandOptions);
+ // If no callback just return
+ if(!callback) return;
+ // If error return error
+ if(result instanceof Error) {
+ return callback(result);
+ }
+ // Otherwise just return
+ return callback(null, null);
+ }
+};
+
+/**
+ * Ensures that an index exists, if it does not it creates it
+ *
+ * Options
+ * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **unique** {Boolean, default:false}, creates an unique index.
+ * - **sparse** {Boolean, default:false}, creates a sparse index.
+ * - **background** {Boolean, default:false}, creates the index in the background, yielding whenever possible.
+ * - **dropDups** {Boolean, default:false}, a unique index cannot be created on a key that has pre-existing duplicate values. If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
+ * - **min** {Number}, for geospatial indexes set the lower bound for the co-ordinates.
+ * - **max** {Number}, for geospatial indexes set the high bound for the co-ordinates.
+ * - **v** {Number}, specify the format version of the indexes.
+ * - **expireAfterSeconds** {Number}, allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
+ * - **name** {String}, override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @param {String} collectionName name of the collection to create the index on.
+ * @param {Object} fieldOrSpec fieldOrSpec that defines the index.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from ensureIndex or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.ensureIndex = function(collectionName, fieldOrSpec, options, callback) {
+ var self = this;
+
+ if (typeof callback === 'undefined' && typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ if (options == null) {
+ options = {};
+ }
+
+ // Get the error options
+ var errorOptions = _getWriteConcern(this, options, callback);
+ // Make sure we don't try to do a write concern without a callback
+ if(_hasWriteConcern(errorOptions) && callback == null)
+ throw new Error("Cannot use a writeConcern without a provided callback");
+ // Create command
+ var command = DbCommand.createCreateIndexCommand(this, collectionName, fieldOrSpec, options);
+ var index_name = command.documents[0].name;
+
+ // Default command options
+ var commandOptions = {};
+ // Check if the index allready exists
+ this.indexInformation(collectionName, function(err, collectionInfo) {
+ if(err != null) return callback(err, null);
+
+ if(!collectionInfo[index_name]) {
+ // If we have error conditions set handle them
+ if(_hasWriteConcern(errorOptions) && typeof callback == 'function') {
+ // Insert options
+ commandOptions['read'] = false;
+ // If we have safe set set async to false
+ if(errorOptions == null) commandOptions['async'] = true;
+
+ // If we have an error option
+ if(typeof errorOptions == 'object') {
+ var keys = Object.keys(errorOptions);
+ for(var i = 0; i < keys.length; i++) {
+ commandOptions[keys[i]] = errorOptions[keys[i]];
+ }
+ }
+
+ if(typeof callback === 'function'
+ && commandOptions.w < 1 && !commandOptions.fsync && !commandOptions.journal) {
+ commandOptions.w = 1;
+ }
+
+ self._executeInsertCommand(command, commandOptions, function(err, result) {
+ // Only callback if we have one specified
+ if(typeof callback === 'function') {
+ if(err != null) return callback(err, null);
+
+ result = result && result.documents;
+ if (result[0].err) {
+ callback(utils.toError(result[0]));
+ } else {
+ callback(null, command.documents[0].name);
+ }
+ }
+ });
+ } else {
+ // Execute insert command
+ var result = self._executeInsertCommand(command, commandOptions);
+ // If no callback just return
+ if(!callback) return;
+ // If error return error
+ if(result instanceof Error) {
+ return callback(result);
+ }
+ // Otherwise just return
+ return callback(null, index_name);
+ }
+ } else {
+ if(typeof callback === 'function') return callback(null, index_name);
+ }
+ });
+};
+
+/**
+ * Returns the information available on allocated cursors.
+ *
+ * Options
+ * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ *
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from cursorInfo or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.cursorInfo = function(options, callback) {
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ options = args.length ? args.shift() || {} : {};
+
+ this._executeQueryCommand(DbCommand.createDbSlaveOkCommand(this, {'cursorInfo':1}), options, function(err, result) {
+ callback(err, result.documents[0]);
+ });
+};
+
+/**
+ * Drop an index on a collection.
+ *
+ * @param {String} collectionName the name of the collection where the command will drop an index.
+ * @param {String} indexName name of the index to drop.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from dropIndex or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.dropIndex = function(collectionName, indexName, callback) {
+ this._executeQueryCommand(DbCommand.createDropIndexCommand(this, collectionName, indexName), callback);
+};
+
+/**
+ * Reindex all indexes on the collection
+ * Warning: reIndex is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections.
+ *
+ * @param {String} collectionName the name of the collection.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from reIndex or null if an error occured.
+ * @api public
+**/
+Db.prototype.reIndex = function(collectionName, callback) {
+ this._executeQueryCommand(DbCommand.createReIndexCommand(this, collectionName), function(err, result) {
+ if(err != null) {
+ callback(err, false);
+ } else if(result.documents[0].errmsg == null) {
+ callback(null, true);
+ } else {
+ callback(new Error(result.documents[0].errmsg), false);
+ }
+ });
+};
+
+/**
+ * Retrieves this collections index info.
+ *
+ * Options
+ * - **full** {Boolean, default:false}, returns the full raw index information.
+ * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ *
+ * @param {String} collectionName the name of the collection.
+ * @param {Object} [options] additional options during update.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from indexInformation or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.indexInformation = function(collectionName, options, callback) {
+ if(typeof callback === 'undefined') {
+ if(typeof options === 'undefined') {
+ callback = collectionName;
+ collectionName = null;
+ } else {
+ callback = options;
+ }
+ options = {};
+ }
+
+ // If we specified full information
+ var full = options['full'] == null ? false : options['full'];
+ // Build selector for the indexes
+ var selector = collectionName != null ? {ns: (this.databaseName + "." + collectionName)} : {};
+
+ // Set read preference if we set one
+ var readPreference = options['readPreference'] ? options['readPreference'] : ReadPreference.PRIMARY;
+
+ // Iterate through all the fields of the index
+ this.collection(DbCommand.SYSTEM_INDEX_COLLECTION, function(err, collection) {
+ // Perform the find for the collection
+ collection.find(selector).setReadPreference(readPreference).toArray(function(err, indexes) {
+ if(err != null) return callback(err, null);
+ // Contains all the information
+ var info = {};
+
+ // if full defined just return all the indexes directly
+ if(full) return callback(null, indexes);
+
+ // Process all the indexes
+ for(var i = 0; i < indexes.length; i++) {
+ var index = indexes[i];
+ // Let's unpack the object
+ info[index.name] = [];
+ for(var name in index.key) {
+ info[index.name].push([name, index.key[name]]);
+ }
+ }
+
+ // Return all the indexes
+ callback(null, info);
+ });
+ });
+};
+
+/**
+ * Drop a database.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from dropDatabase or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.dropDatabase = function(callback) {
+ var self = this;
+
+ this._executeQueryCommand(DbCommand.createDropDatabaseCommand(this), function(err, result) {
+ if(err == null && result.documents[0].ok == 1) {
+ callback(null, true);
+ } else {
+ if(err) {
+ callback(err, false);
+ } else {
+ callback(utils.toError(result.documents[0]), false);
+ }
+ }
+ });
+};
+
+/**
+ * Get all the db statistics.
+ *
+ * Options
+ * - **scale** {Number}, divide the returned sizes by scale value.
+ * - **readPreference** {String}, the preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
+ *
+ * @param {Objects} [options] options for the stats command
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from stats or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.prototype.stats = function stats(options, callback) {
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ // Fetch all commands
+ options = args.length ? args.shift() || {} : {};
+
+ // Build command object
+ var commandObject = {
+ dbStats:this.collectionName,
+ }
+
+ // Check if we have the scale value
+ if(options['scale'] != null) commandObject['scale'] = options['scale'];
+
+ // Execute the command
+ this.command(commandObject, options, callback);
+}
+
+/**
+ * @ignore
+ */
+var __executeQueryCommand = function(self, db_command, options, callback) {
+ // Options unpacking
+ var read = options['read'] != null ? options['read'] : false;
+ var raw = options['raw'] != null ? options['raw'] : self.raw;
+ var onAll = options['onAll'] != null ? options['onAll'] : false;
+ var specifiedConnection = options['connection'] != null ? options['connection'] : null;
+
+ // Correct read preference to default primary if set to false, null or primary
+ if(!(typeof read == 'object') && read._type == 'ReadPreference') {
+ read = (read == null || read == 'primary' || read == false) ? ReadPreference.PRIMARY : read;
+ if(!ReadPreference.isValid(read)) return callback(new Error("Illegal readPreference mode specified, " + read));
+ } else if(typeof read == 'object' && read._type == 'ReadPreference') {
+ if(!read.isValid()) return callback(new Error("Illegal readPreference mode specified, " + read.mode));
+ }
+
+ // If we have a read preference set and we are a mongos pass the read preference on to the mongos instance,
+ if(self.serverConfig.isMongos() && read != null && read != false) {
+ db_command.setMongosReadPreference(read);
+ }
+
+ // If we got a callback object
+ if(typeof callback === 'function' && !onAll) {
+ // Override connection if we passed in a specific connection
+ var connection = specifiedConnection != null ? specifiedConnection : null;
+
+ if(connection instanceof Error) return callback(connection, null);
+
+ // Fetch either a reader or writer dependent on the specified read option if no connection
+ // was passed in
+ if(connection == null) {
+ connection = self.serverConfig.checkoutReader(read);
+ }
+
+ if(connection == null) {
+ return callback(new Error("no open connections"));
+ } else if(connection instanceof Error || connection['message'] != null) {
+ return callback(connection);
+ }
+
+ // Exhaust Option
+ var exhaust = options.exhaust || false;
+
+ // Register the handler in the data structure
+ self.serverConfig._registerHandler(db_command, raw, connection, exhaust, callback);
+
+ // Ensure the connection is valid
+ if(!connection.isConnected()) {
+ if(read == ReadPreference.PRIMARY
+ || read == ReadPreference.PRIMARY_PREFERRED
+ || (read != null && typeof read == 'object' && read.mode)
+ || read == null) {
+
+ // Save the command
+ self.serverConfig._commandsStore.read_from_writer(
+ { type: 'query'
+ , db_command: db_command
+ , options: options
+ , callback: callback
+ , db: self
+ , executeQueryCommand: __executeQueryCommand
+ , executeInsertCommand: __executeInsertCommand
+ }
+ );
+ } else {
+ self.serverConfig._commandsStore.read(
+ { type: 'query'
+ , db_command: db_command
+ , options: options
+ , callback: callback
+ , db: self
+ , executeQueryCommand: __executeQueryCommand
+ , executeInsertCommand: __executeInsertCommand
+ }
+ );
+ }
+ }
+
+ // Write the message out and handle any errors if there are any
+ connection.write(db_command, function(err) {
+ if(err != null) {
+ // Call the handler with an error
+ if(Array.isArray(db_command))
+ self.serverConfig._callHandler(db_command[0].getRequestId(), null, err);
+ else
+ self.serverConfig._callHandler(db_command.getRequestId(), null, err);
+ }
+ });
+ } else if(typeof callback === 'function' && onAll) {
+ var connections = self.serverConfig.allRawConnections();
+ var numberOfEntries = connections.length;
+ // Go through all the connections
+ for(var i = 0; i < connections.length; i++) {
+ // Fetch a connection
+ var connection = connections[i];
+
+ // Ensure we have a valid connection
+ if(connection == null) {
+ return callback(new Error("no open connections"));
+ } else if(connection instanceof Error) {
+ return callback(connection);
+ }
+
+ // Register the handler in the data structure
+ self.serverConfig._registerHandler(db_command, raw, connection, callback);
+
+ // Write the message out
+ connection.write(db_command, function(err) {
+ // Adjust the number of entries we need to process
+ numberOfEntries = numberOfEntries - 1;
+ // Remove listener
+ if(err != null) {
+ // Clean up listener and return error
+ self.serverConfig._removeHandler(db_command.getRequestId());
+ }
+
+ // No more entries to process callback with the error
+ if(numberOfEntries <= 0) {
+ callback(err);
+ }
+ });
+
+ // Update the db_command request id
+ db_command.updateRequestId();
+ }
+ } else {
+ // Fetch either a reader or writer dependent on the specified read option
+ // var connection = read == null || read == 'primary' || read == false ? self.serverConfig.checkoutWriter(true) : self.serverConfig.checkoutReader(read);
+ var connection = self.serverConfig.checkoutReader(read);
+ // Override connection if needed
+ connection = specifiedConnection != null ? specifiedConnection : connection;
+ // Ensure we have a valid connection
+ if(connection == null || connection instanceof Error || connection['message'] != null) return null;
+ // Write the message out
+ connection.write(db_command, function(err) {
+ if(err != null) {
+ // Emit the error
+ self.emit("error", err);
+ }
+ });
+ }
+}
+
+/**
+ * Execute db query command (not safe)
+ * @ignore
+ * @api private
+ */
+Db.prototype._executeQueryCommand = function(db_command, options, callback) {
+ var self = this;
+
+ // Unpack the parameters
+ if (typeof callback === 'undefined') {
+ callback = options;
+ options = {};
+ }
+
+ // fast fail option used for HA, no retry
+ var failFast = options['failFast'] != null
+ ? options['failFast']
+ : false;
+
+ // Check if the user force closed the command
+ if(this._applicationClosed) {
+ var err = new Error("db closed by application");
+ if('function' == typeof callback) {
+ return callback(err, null);
+ } else {
+ throw err;
+ }
+ }
+
+ if(this.serverConfig.isDestroyed()) return callback(new Error("Connection was destroyed by application"));
+
+ // Get the configuration
+ var config = this.serverConfig;
+ var read = options.read;
+
+ if(!config.canRead(read) && !config.canWrite() && config.isAutoReconnect()) {
+ if(read == ReadPreference.PRIMARY
+ || read == ReadPreference.PRIMARY_PREFERRED
+ || (read != null && typeof read == 'object' && read.mode)
+ || read == null) {
+
+ // Save the command
+ self.serverConfig._commandsStore.read_from_writer(
+ { type: 'query'
+ , db_command: db_command
+ , options: options
+ , callback: callback
+ , db: self
+ , executeQueryCommand: __executeQueryCommand
+ , executeInsertCommand: __executeInsertCommand
+ }
+ );
+ } else {
+ self.serverConfig._commandsStore.read(
+ { type: 'query'
+ , db_command: db_command
+ , options: options
+ , callback: callback
+ , db: self
+ , executeQueryCommand: __executeQueryCommand
+ , executeInsertCommand: __executeInsertCommand
+ }
+ );
+ }
+ } else if(!config.canRead(read) && !config.canWrite() && !config.isAutoReconnect()) {
+ return callback(new Error("no open connections"), null);
+ } else {
+ // Execute the command
+ __executeQueryCommand(self, db_command, options, function (err, result, conn) {
+ if(callback) callback(err, result, conn);
+ });
+ }
+};
+
+/**
+ * @ignore
+ */
+var __executeInsertCommand = function(self, db_command, options, callback) {
+ // Always checkout a writer for this kind of operations
+ var connection = self.serverConfig.checkoutWriter();
+ // Get safe mode
+ var safe = options['safe'] != null ? options['safe'] : false;
+ var raw = options['raw'] != null ? options['raw'] : self.raw;
+ var specifiedConnection = options['connection'] != null ? options['connection'] : null;
+ // Override connection if needed
+ connection = specifiedConnection != null ? specifiedConnection : connection;
+
+ // Ensure we have a valid connection
+ if(typeof callback === 'function') {
+ // Ensure we have a valid connection
+ /*if(connection == null && self.serverConfig.isAutoReconnect()) {
+ return self.serverConfig._commandsStore.write(
+ { type:'insert'
+ , 'db_command':db_command
+ , 'options':options
+ , 'callback':callback
+ , db: self
+ , executeQueryCommand: __executeQueryCommand
+ , executeInsertCommand: __executeInsertCommand
+ }
+ );
+ } else*/ if(connection == null) {
+ return callback(new Error("no open connections"));
+ } else if(connection instanceof Error) {
+ return callback(connection);
+ }
+
+ var errorOptions = _getWriteConcern(self, options, callback);
+ if(errorOptions.w > 0 || errorOptions.w == 'majority' || errorOptions.j || errorOptions.journal || errorOptions.fsync) {
+ // db command is now an array of commands (original command + lastError)
+ db_command = [db_command, DbCommand.createGetLastErrorCommand(safe, self)];
+ // Register the handler in the data structure
+ self.serverConfig._registerHandler(db_command[1], raw, connection, callback);
+ }
+ }
+
+ // If we have no callback and there is no connection
+ if(connection == null) return null;
+ if(connection instanceof Error && typeof callback == 'function') return callback(connection, null);
+ if(connection instanceof Error) return null;
+ if(connection == null && typeof callback == 'function') return callback(new Error("no primary server found"), null);
+
+ // Ensure we truly are connected
+ if(!connection.isConnected()) {
+ return self.serverConfig._commandsStore.write(
+ { type:'insert'
+ , 'db_command':db_command
+ , 'options':options
+ , 'callback':callback
+ , db: self
+ , executeQueryCommand: __executeQueryCommand
+ , executeInsertCommand: __executeInsertCommand
+ }
+ );
+ }
+
+ // Write the message out
+ connection.write(db_command, function(err) {
+ // Return the callback if it's not a safe operation and the callback is defined
+ if(typeof callback === 'function' && (safe == null || safe == false)) {
+ // Perform the callback
+ callback(err, null);
+ } else if(typeof callback === 'function') {
+ // Call the handler with an error
+ self.serverConfig._callHandler(db_command[1].getRequestId(), null, err);
+ } else if(typeof callback == 'function' && safe && safe.w == -1) {
+ // Call the handler with no error
+ self.serverConfig._callHandler(db_command[1].getRequestId(), null, null);
+ } else if(!safe || safe.w == -1) {
+ self.emit("error", err);
+ }
+ });
+}
+
+/**
+ * Execute an insert Command
+ * @ignore
+ * @api private
+ */
+Db.prototype._executeInsertCommand = function(db_command, options, callback) {
+ var self = this;
+
+ // Unpack the parameters
+ if(callback == null && typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+
+ // Ensure options are not null
+ options = options == null ? {} : options;
+
+ // Check if the user force closed the command
+ if(this._applicationClosed) {
+ if(typeof callback == 'function') {
+ return callback(new Error("db closed by application"), null);
+ } else {
+ throw new Error("db closed by application");
+ }
+ }
+
+ if(this.serverConfig.isDestroyed()) return callback(new Error("Connection was destroyed by application"));
+
+ // Get config
+ var config = self.serverConfig;
+ // Check if we are connected
+ if(!config.canWrite() && config.isAutoReconnect()) {
+ self.serverConfig._commandsStore.write(
+ { type:'insert'
+ , 'db_command':db_command
+ , 'options':options
+ , 'callback':callback
+ , db: self
+ , executeQueryCommand: __executeQueryCommand
+ , executeInsertCommand: __executeInsertCommand
+ }
+ );
+ } else if(!config.canWrite() && !config.isAutoReconnect()) {
+ return callback(new Error("no open connections"), null);
+ } else {
+ // Execute write command
+ __executeInsertCommand(self, db_command, options, callback);
+ }
+}
+
+/**
+ * Update command is the same
+ * @ignore
+ * @api private
+ */
+Db.prototype._executeUpdateCommand = Db.prototype._executeInsertCommand;
+/**
+ * Remove command is the same
+ * @ignore
+ * @api private
+ */
+Db.prototype._executeRemoveCommand = Db.prototype._executeInsertCommand;
+
+/**
+ * Wrap a Mongo error document into an Error instance.
+ * Deprecated. Use utils.toError instead.
+ *
+ * @ignore
+ * @api private
+ * @deprecated
+ */
+Db.prototype.wrap = utils.toError;
+
+/**
+ * Default URL
+ *
+ * @classconstant DEFAULT_URL
+ **/
+Db.DEFAULT_URL = 'mongodb://localhost:27017/default';
+
+/**
+ * Connect to MongoDB using a url as documented at
+ *
+ * docs.mongodb.org/manual/reference/connection-string/
+ *
+ * Options
+ * - **uri_decode_auth** {Boolean, default:false} uri decode the user name and password for authentication
+ * - **db** {Object, default: null} a hash off options to set on the db object, see **Db constructor**
+ * - **server** {Object, default: null} a hash off options to set on the server objects, see **Server** constructor**
+ * - **replSet** {Object, default: null} a hash off options to set on the replSet object, see **ReplSet** constructor**
+ * - **mongos** {Object, default: null} a hash off options to set on the mongos object, see **Mongos** constructor**
+ *
+ * @param {String} url connection url for MongoDB.
+ * @param {Object} [options] optional options for insert command
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the db instance or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+Db.connect = function(url, options, callback) {
+ // Ensure correct mapping of the callback
+ if(typeof options == 'function') {
+ callback = options;
+ options = {};
+ }
+
+ // Ensure same behavior as previous version w:0
+ if(url.indexOf("safe") == -1
+ && url.indexOf("w") == -1
+ && url.indexOf("journal") == -1 && url.indexOf("j") == -1
+ && url.indexOf("fsync") == -1) options.w = 0;
+
+ // Avoid circular require problem
+ var MongoClient = require('./mongo_client.js').MongoClient;
+ // Attempt to connect
+ MongoClient.connect.call(MongoClient, url, options, callback);
+}
+
+/**
+ * State of the db connection
+ * @ignore
+ */
+Object.defineProperty(Db.prototype, "state", { enumerable: true
+ , get: function () {
+ return this.serverConfig._serverState;
+ }
+});
+
+/**
+ * @ignore
+ */
+var _hasWriteConcern = function(errorOptions) {
+ return errorOptions == true
+ || errorOptions.w > 0
+ || errorOptions.w == 'majority'
+ || errorOptions.j == true
+ || errorOptions.journal == true
+ || errorOptions.fsync == true
+}
+
+/**
+ * @ignore
+ */
+var _setWriteConcernHash = function(options) {
+ var finalOptions = {};
+ if(options.w != null) finalOptions.w = options.w;
+ if(options.journal == true) finalOptions.j = options.journal;
+ if(options.j == true) finalOptions.j = options.j;
+ if(options.fsync == true) finalOptions.fsync = options.fsync;
+ if(options.wtimeout != null) finalOptions.wtimeout = options.wtimeout;
+ return finalOptions;
+}
+
+/**
+ * @ignore
+ */
+var _getWriteConcern = function(self, options, callback) {
+ // Final options
+ var finalOptions = {w:1};
+ // Local options verification
+ if(options.w != null || typeof options.j == 'boolean' || typeof options.journal == 'boolean' || typeof options.fsync == 'boolean') {
+ finalOptions = _setWriteConcernHash(options);
+ } else if(options.safe != null && typeof options.safe == 'object') {
+ finalOptions = _setWriteConcernHash(options.safe);
+ } else if(typeof options.safe == "boolean") {
+ finalOptions = {w: (options.safe ? 1 : 0)};
+ } else if(self.options.w != null || typeof self.options.j == 'boolean' || typeof self.options.journal == 'boolean' || typeof self.options.fsync == 'boolean') {
+ finalOptions = _setWriteConcernHash(self.options);
+ } else if(self.safe.w != null || typeof self.safe.j == 'boolean' || typeof self.safe.journal == 'boolean' || typeof self.safe.fsync == 'boolean') {
+ finalOptions = _setWriteConcernHash(self.safe);
+ } else if(typeof self.safe == "boolean") {
+ finalOptions = {w: (self.safe ? 1 : 0)};
+ }
+
+ // Ensure we don't have an invalid combination of write concerns
+ if(finalOptions.w < 1
+ && (finalOptions.journal == true || finalOptions.j == true || finalOptions.fsync == true)) throw new Error("No acknowlegement using w < 1 cannot be combined with journal:true or fsync:true");
+
+ // Return the options
+ return finalOptions;
+}
+
+/**
+ * Legacy support
+ *
+ * @ignore
+ * @api private
+ */
+exports.connect = Db.connect;
+exports.Db = Db;
+
+/**
+ * Remove all listeners to the db instance.
+ * @ignore
+ * @api private
+ */
+Db.prototype.removeAllEventListeners = function() {
+ this.removeAllListeners("close");
+ this.removeAllListeners("error");
+ this.removeAllListeners("timeout");
+ this.removeAllListeners("parseError");
+ this.removeAllListeners("poolReady");
+ this.removeAllListeners("message");
+}
diff --git a/node_modules/mongodb/lib/mongodb/gridfs/chunk.js b/node_modules/mongodb/lib/mongodb/gridfs/chunk.js
new file mode 100644
index 0000000..59c6a26
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/gridfs/chunk.js
@@ -0,0 +1,221 @@
+var Binary = require('bson').Binary,
+ ObjectID = require('bson').ObjectID;
+
+/**
+ * Class for representing a single chunk in GridFS.
+ *
+ * @class
+ *
+ * @param file {GridStore} The {@link GridStore} object holding this chunk.
+ * @param mongoObject {object} The mongo object representation of this chunk.
+ *
+ * @throws Error when the type of data field for {@link mongoObject} is not
+ * supported. Currently supported types for data field are instances of
+ * {@link String}, {@link Array}, {@link Binary} and {@link Binary}
+ * from the bson module
+ *
+ * @see Chunk#buildMongoObject
+ */
+var Chunk = exports.Chunk = function(file, mongoObject, writeConcern) {
+ if(!(this instanceof Chunk)) return new Chunk(file, mongoObject);
+
+ this.file = file;
+ var self = this;
+ var mongoObjectFinal = mongoObject == null ? {} : mongoObject;
+ this.writeConcern = writeConcern || {w:1};
+ this.objectId = mongoObjectFinal._id == null ? new ObjectID() : mongoObjectFinal._id;
+ this.chunkNumber = mongoObjectFinal.n == null ? 0 : mongoObjectFinal.n;
+ this.data = new Binary();
+
+ if(mongoObjectFinal.data == null) {
+ } else if(typeof mongoObjectFinal.data == "string") {
+ var buffer = new Buffer(mongoObjectFinal.data.length);
+ buffer.write(mongoObjectFinal.data, 'binary', 0);
+ this.data = new Binary(buffer);
+ } else if(Array.isArray(mongoObjectFinal.data)) {
+ var buffer = new Buffer(mongoObjectFinal.data.length);
+ buffer.write(mongoObjectFinal.data.join(''), 'binary', 0);
+ this.data = new Binary(buffer);
+ } else if(mongoObjectFinal.data instanceof Binary || Object.prototype.toString.call(mongoObjectFinal.data) == "[object Binary]") {
+ this.data = mongoObjectFinal.data;
+ } else if(Buffer.isBuffer(mongoObjectFinal.data)) {
+ } else {
+ throw Error("Illegal chunk format");
+ }
+ // Update position
+ this.internalPosition = 0;
+};
+
+/**
+ * Writes a data to this object and advance the read/write head.
+ *
+ * @param data {string} the data to write
+ * @param callback {function(*, GridStore)} This will be called after executing
+ * this method. The first parameter will contain null and the second one
+ * will contain a reference to this object.
+ */
+Chunk.prototype.write = function(data, callback) {
+ this.data.write(data, this.internalPosition);
+ this.internalPosition = this.data.length();
+ if(callback != null) return callback(null, this);
+ return this;
+};
+
+/**
+ * Reads data and advances the read/write head.
+ *
+ * @param length {number} The length of data to read.
+ *
+ * @return {string} The data read if the given length will not exceed the end of
+ * the chunk. Returns an empty String otherwise.
+ */
+Chunk.prototype.read = function(length) {
+ // Default to full read if no index defined
+ length = length == null || length == 0 ? this.length() : length;
+
+ if(this.length() - this.internalPosition + 1 >= length) {
+ var data = this.data.read(this.internalPosition, length);
+ this.internalPosition = this.internalPosition + length;
+ return data;
+ } else {
+ return '';
+ }
+};
+
+Chunk.prototype.readSlice = function(length) {
+ if ((this.length() - this.internalPosition) >= length) {
+ var data = null;
+ if (this.data.buffer != null) { //Pure BSON
+ data = this.data.buffer.slice(this.internalPosition, this.internalPosition + length);
+ } else { //Native BSON
+ data = new Buffer(length);
+ length = this.data.readInto(data, this.internalPosition);
+ }
+ this.internalPosition = this.internalPosition + length;
+ return data;
+ } else {
+ return null;
+ }
+};
+
+/**
+ * Checks if the read/write head is at the end.
+ *
+ * @return {boolean} Whether the read/write head has reached the end of this
+ * chunk.
+ */
+Chunk.prototype.eof = function() {
+ return this.internalPosition == this.length() ? true : false;
+};
+
+/**
+ * Reads one character from the data of this chunk and advances the read/write
+ * head.
+ *
+ * @return {string} a single character data read if the the read/write head is
+ * not at the end of the chunk. Returns an empty String otherwise.
+ */
+Chunk.prototype.getc = function() {
+ return this.read(1);
+};
+
+/**
+ * Clears the contents of the data in this chunk and resets the read/write head
+ * to the initial position.
+ */
+Chunk.prototype.rewind = function() {
+ this.internalPosition = 0;
+ this.data = new Binary();
+};
+
+/**
+ * Saves this chunk to the database. Also overwrites existing entries having the
+ * same id as this chunk.
+ *
+ * @param callback {function(*, GridStore)} This will be called after executing
+ * this method. The first parameter will contain null and the second one
+ * will contain a reference to this object.
+ */
+Chunk.prototype.save = function(callback) {
+ var self = this;
+
+ self.file.chunkCollection(function(err, collection) {
+ if(err) return callback(err);
+
+ collection.remove({'_id':self.objectId}, self.writeConcern, function(err, result) {
+ if(err) return callback(err);
+
+ if(self.data.length() > 0) {
+ self.buildMongoObject(function(mongoObject) {
+ var options = {forceServerObjectId:true};
+ for(var name in self.writeConcern) {
+ options[name] = self.writeConcern[name];
+ }
+
+ collection.insert(mongoObject, options, function(err, collection) {
+ callback(err, self);
+ });
+ });
+ } else {
+ callback(null, self);
+ }
+ });
+ });
+};
+
+/**
+ * Creates a mongoDB object representation of this chunk.
+ *
+ * @param callback {function(Object)} This will be called after executing this
+ * method. The object will be passed to the first parameter and will have
+ * the structure:
+ *
+ *
+ * {
+ * '_id' : , // {number} id for this chunk
+ * 'files_id' : , // {number} foreign key to the file collection
+ * 'n' : , // {number} chunk number
+ * 'data' : , // {bson#Binary} the chunk data itself
+ * }
+ *
+ *
+ * @see MongoDB GridFS Chunk Object Structure
+ */
+Chunk.prototype.buildMongoObject = function(callback) {
+ var mongoObject = {
+ 'files_id': this.file.fileId,
+ 'n': this.chunkNumber,
+ 'data': this.data};
+ // If we are saving using a specific ObjectId
+ if(this.objectId != null) mongoObject._id = this.objectId;
+
+ callback(mongoObject);
+};
+
+/**
+ * @return {number} the length of the data
+ */
+Chunk.prototype.length = function() {
+ return this.data.length();
+};
+
+/**
+ * The position of the read/write head
+ * @name position
+ * @lends Chunk#
+ * @field
+ */
+Object.defineProperty(Chunk.prototype, "position", { enumerable: true
+ , get: function () {
+ return this.internalPosition;
+ }
+ , set: function(value) {
+ this.internalPosition = value;
+ }
+});
+
+/**
+ * The default chunk size
+ * @constant
+ */
+Chunk.DEFAULT_CHUNK_SIZE = 1024 * 256;
diff --git a/node_modules/mongodb/lib/mongodb/gridfs/grid.js b/node_modules/mongodb/lib/mongodb/gridfs/grid.js
new file mode 100644
index 0000000..aa695b7
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/gridfs/grid.js
@@ -0,0 +1,103 @@
+var GridStore = require('./gridstore').GridStore,
+ ObjectID = require('bson').ObjectID;
+
+/**
+ * A class representation of a simple Grid interface.
+ *
+ * @class Represents the Grid.
+ * @param {Db} db A database instance to interact with.
+ * @param {String} [fsName] optional different root collection for GridFS.
+ * @return {Grid}
+ */
+function Grid(db, fsName) {
+
+ if(!(this instanceof Grid)) return new Grid(db, fsName);
+
+ this.db = db;
+ this.fsName = fsName == null ? GridStore.DEFAULT_ROOT_COLLECTION : fsName;
+}
+
+/**
+ * Puts binary data to the grid
+ *
+ * Options
+ * - **_id** {Any}, unique id for this file
+ * - **root** {String}, root collection to use. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**.
+ * - **content_type** {String}, mime type of the file. Defaults to **{GridStore.DEFAULT_CONTENT_TYPE}**.
+ * - **chunk_size** {Number}, size for the chunk. Defaults to **{Chunk.DEFAULT_CHUNK_SIZE}**.
+ * - **metadata** {Object}, arbitrary data the user wants to store.
+ *
+ * @param {Buffer} data buffer with Binary Data.
+ * @param {Object} [options] the options for the files.
+ * @param {Function} callback this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object.
+ * @return {null}
+ * @api public
+ */
+Grid.prototype.put = function(data, options, callback) {
+ var self = this;
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ options = args.length ? args.shift() : {};
+ // If root is not defined add our default one
+ options['root'] = options['root'] == null ? this.fsName : options['root'];
+
+ // Return if we don't have a buffer object as data
+ if(!(Buffer.isBuffer(data))) return callback(new Error("Data object must be a buffer object"), null);
+ // Get filename if we are using it
+ var filename = options['filename'] || null;
+ // Get id if we are using it
+ var id = options['_id'] || null;
+ // Create gridstore
+ var gridStore = new GridStore(this.db, id, filename, "w", options);
+ gridStore.open(function(err, gridStore) {
+ if(err) return callback(err, null);
+
+ gridStore.write(data, function(err, result) {
+ if(err) return callback(err, null);
+
+ gridStore.close(function(err, result) {
+ if(err) return callback(err, null);
+ callback(null, result);
+ })
+ })
+ })
+}
+
+/**
+ * Get binary data to the grid
+ *
+ * @param {Any} id for file.
+ * @param {Function} callback this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object.
+ * @return {null}
+ * @api public
+ */
+Grid.prototype.get = function(id, callback) {
+ // Create gridstore
+ var gridStore = new GridStore(this.db, id, null, "r", {root:this.fsName});
+ gridStore.open(function(err, gridStore) {
+ if(err) return callback(err, null);
+
+ // Return the data
+ gridStore.read(function(err, data) {
+ return callback(err, data)
+ });
+ })
+}
+
+/**
+ * Delete file from grid
+ *
+ * @param {Any} id for file.
+ * @param {Function} callback this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object.
+ * @return {null}
+ * @api public
+ */
+Grid.prototype.delete = function(id, callback) {
+ // Create gridstore
+ GridStore.unlink(this.db, id, {root:this.fsName}, function(err, result) {
+ if(err) return callback(err, false);
+ return callback(null, true);
+ });
+}
+
+exports.Grid = Grid;
diff --git a/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js b/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js
new file mode 100644
index 0000000..339da72
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/gridfs/gridstore.js
@@ -0,0 +1,1559 @@
+/**
+ * @fileOverview GridFS is a tool for MongoDB to store files to the database.
+ * Because of the restrictions of the object size the database can hold, a
+ * facility to split a file into several chunks is needed. The {@link GridStore}
+ * class offers a simplified api to interact with files while managing the
+ * chunks of split files behind the scenes. More information about GridFS can be
+ * found here.
+ */
+var Chunk = require('./chunk').Chunk,
+ DbCommand = require('../commands/db_command').DbCommand,
+ ObjectID = require('bson').ObjectID,
+ Buffer = require('buffer').Buffer,
+ fs = require('fs'),
+ timers = require('timers'),
+ util = require('util'),
+ inherits = util.inherits,
+ ReadStream = require('./readstream').ReadStream,
+ Stream = require('stream');
+
+// Set processor, setImmediate if 0.10 otherwise nextTick
+var processor = timers.setImmediate ? timers.setImmediate : process.nextTick;
+processor = process.nextTick
+
+var REFERENCE_BY_FILENAME = 0,
+ REFERENCE_BY_ID = 1;
+
+/**
+ * A class representation of a file stored in GridFS.
+ *
+ * Modes
+ * - **"r"** - read only. This is the default mode.
+ * - **"w"** - write in truncate mode. Existing data will be overwriten.
+ * - **w+"** - write in edit mode.
+ *
+ * Options
+ * - **root** {String}, root collection to use. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**.
+ * - **content_type** {String}, mime type of the file. Defaults to **{GridStore.DEFAULT_CONTENT_TYPE}**.
+ * - **chunk_size** {Number}, size for the chunk. Defaults to **{Chunk.DEFAULT_CHUNK_SIZE}**.
+ * - **metadata** {Object}, arbitrary data the user wants to store.
+ * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ *
+ * @class Represents the GridStore.
+ * @param {Db} db A database instance to interact with.
+ * @param {Any} [id] optional unique id for this file
+ * @param {String} [filename] optional filename for this file, no unique constrain on the field
+ * @param {String} mode set the mode for this file.
+ * @param {Object} options optional properties to specify.
+ * @return {GridStore}
+ */
+var GridStore = function GridStore(db, id, filename, mode, options) {
+ if(!(this instanceof GridStore)) return new GridStore(db, id, filename, mode, options);
+
+ var self = this;
+ this.db = db;
+
+ // Call stream constructor
+ if(typeof Stream == 'function') {
+ Stream.call(this);
+ } else {
+ // 0.4.X backward compatibility fix
+ Stream.Stream.call(this);
+ }
+
+ // Handle options
+ if(typeof options === 'undefined') options = {};
+ // Handle mode
+ if(typeof mode === 'undefined') {
+ mode = filename;
+ filename = undefined;
+ } else if(typeof mode == 'object') {
+ options = mode;
+ mode = filename;
+ filename = undefined;
+ }
+
+ if(id instanceof ObjectID) {
+ this.referenceBy = REFERENCE_BY_ID;
+ this.fileId = id;
+ this.filename = filename;
+ } else if(typeof filename == 'undefined') {
+ this.referenceBy = REFERENCE_BY_FILENAME;
+ this.filename = id;
+ if (mode.indexOf('w') != null) {
+ this.fileId = new ObjectID();
+ }
+ } else {
+ this.referenceBy = REFERENCE_BY_ID;
+ this.fileId = id;
+ this.filename = filename;
+ }
+
+ // Set up the rest
+ this.mode = mode == null ? "r" : mode;
+ this.options = options == null ? {w:1} : options;
+
+ // If we have no write concerns set w:1 as default
+ if(this.options.w == null
+ && this.options.j == null
+ && this.options.fsync == null) this.options.w = 1;
+
+ // Set the root if overridden
+ this.root = this.options['root'] == null ? exports.GridStore.DEFAULT_ROOT_COLLECTION : this.options['root'];
+ this.position = 0;
+ this.readPreference = this.options.readPreference || 'primary';
+ this.writeConcern = _getWriteConcern(this, this.options);
+ // Set default chunk size
+ this.internalChunkSize = this.options['chunkSize'] == null ? Chunk.DEFAULT_CHUNK_SIZE : this.options['chunkSize'];
+}
+
+/**
+ * Code for the streaming capabilities of the gridstore object
+ * Most code from Aaron heckmanns project https://github.com/aheckmann/gridfs-stream
+ * Modified to work on the gridstore object itself
+ * @ignore
+ */
+if(typeof Stream == 'function') {
+ GridStore.prototype = { __proto__: Stream.prototype }
+} else {
+ // Node 0.4.X compatibility code
+ GridStore.prototype = { __proto__: Stream.Stream.prototype }
+}
+
+// Move pipe to _pipe
+GridStore.prototype._pipe = GridStore.prototype.pipe;
+
+/**
+ * Opens the file from the database and initialize this object. Also creates a
+ * new one if file does not exist.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain an **{Error}** object and the second parameter will be null if an error occured. Otherwise, the first parameter will be null and the second will contain the reference to this object.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.open = function(callback) {
+ if( this.mode != "w" && this.mode != "w+" && this.mode != "r"){
+ callback(new Error("Illegal mode " + this.mode), null);
+ return;
+ }
+
+ var self = this;
+
+ if((self.mode == "w" || self.mode == "w+") && self.db.serverConfig.primary != null) {
+ // Get files collection
+ self.collection(function(err, collection) {
+ if(err) return callback(err);
+
+ // Put index on filename
+ collection.ensureIndex([['filename', 1]], function(err, index) {
+ if(err) return callback(err);
+
+ // Get chunk collection
+ self.chunkCollection(function(err, chunkCollection) {
+ if(err) return callback(err);
+
+ // Ensure index on chunk collection
+ chunkCollection.ensureIndex([['files_id', 1], ['n', 1]], function(err, index) {
+ if(err) return callback(err);
+ _open(self, callback);
+ });
+ });
+ });
+ });
+ } else {
+ // Open the gridstore
+ _open(self, callback);
+ }
+};
+
+/**
+ * Hidding the _open function
+ * @ignore
+ * @api private
+ */
+var _open = function(self, callback) {
+ self.collection(function(err, collection) {
+ if(err!==null) {
+ callback(new Error("at collection: "+err), null);
+ return;
+ }
+
+ // Create the query
+ var query = self.referenceBy == REFERENCE_BY_ID ? {_id:self.fileId} : {filename:self.filename};
+ query = null == self.fileId && this.filename == null ? null : query;
+
+ // Fetch the chunks
+ if(query != null) {
+ collection.find(query, {readPreference:self.readPreference}, function(err, cursor) {
+ if(err) return error(err);
+
+ // Fetch the file
+ cursor.nextObject(function(err, doc) {
+ if(err) return error(err);
+
+ // Check if the collection for the files exists otherwise prepare the new one
+ if(doc != null) {
+ self.fileId = doc._id;
+ self.filename = doc.filename;
+ self.contentType = doc.contentType;
+ self.internalChunkSize = doc.chunkSize;
+ self.uploadDate = doc.uploadDate;
+ self.aliases = doc.aliases;
+ self.length = doc.length;
+ self.metadata = doc.metadata;
+ self.internalMd5 = doc.md5;
+ } else if (self.mode != 'r') {
+ self.fileId = self.fileId == null ? new ObjectID() : self.fileId;
+ self.contentType = exports.GridStore.DEFAULT_CONTENT_TYPE;
+ self.internalChunkSize = self.internalChunkSize == null ? Chunk.DEFAULT_CHUNK_SIZE : self.internalChunkSize;
+ self.length = 0;
+ } else {
+ self.length = 0;
+ var txtId = self.fileId instanceof ObjectID ? self.fileId.toHexString() : self.fileId;
+ return error(new Error((self.referenceBy == REFERENCE_BY_ID ? txtId : self.filename) + " does not exist", self));
+ }
+
+ // Process the mode of the object
+ if(self.mode == "r") {
+ nthChunk(self, 0, function(err, chunk) {
+ if(err) return error(err);
+ self.currentChunk = chunk;
+ self.position = 0;
+ callback(null, self);
+ });
+ } else if(self.mode == "w") {
+ // Delete any existing chunks
+ deleteChunks(self, function(err, result) {
+ if(err) return error(err);
+ self.currentChunk = new Chunk(self, {'n':0}, self.writeConcern);
+ self.contentType = self.options['content_type'] == null ? self.contentType : self.options['content_type'];
+ self.internalChunkSize = self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size'];
+ self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
+ self.position = 0;
+ callback(null, self);
+ });
+ } else if(self.mode == "w+") {
+ nthChunk(self, lastChunkNumber(self), function(err, chunk) {
+ if(err) return error(err);
+ // Set the current chunk
+ self.currentChunk = chunk == null ? new Chunk(self, {'n':0}, self.writeConcern) : chunk;
+ self.currentChunk.position = self.currentChunk.data.length();
+ self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
+ self.position = self.length;
+ callback(null, self);
+ });
+ }
+ });
+ });
+ } else {
+ // Write only mode
+ self.fileId = null == self.fileId ? new ObjectID() : self.fileId;
+ self.contentType = exports.GridStore.DEFAULT_CONTENT_TYPE;
+ self.internalChunkSize = self.internalChunkSize == null ? Chunk.DEFAULT_CHUNK_SIZE : self.internalChunkSize;
+ self.length = 0;
+
+ self.chunkCollection(function(err, collection2) {
+ if(err) return error(err);
+
+ // No file exists set up write mode
+ if(self.mode == "w") {
+ // Delete any existing chunks
+ deleteChunks(self, function(err, result) {
+ if(err) return error(err);
+ self.currentChunk = new Chunk(self, {'n':0}, self.writeConcern);
+ self.contentType = self.options['content_type'] == null ? self.contentType : self.options['content_type'];
+ self.internalChunkSize = self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size'];
+ self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
+ self.position = 0;
+ callback(null, self);
+ });
+ } else if(self.mode == "w+") {
+ nthChunk(self, lastChunkNumber(self), function(err, chunk) {
+ if(err) return error(err);
+ // Set the current chunk
+ self.currentChunk = chunk == null ? new Chunk(self, {'n':0}, self.writeConcern) : chunk;
+ self.currentChunk.position = self.currentChunk.data.length();
+ self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
+ self.position = self.length;
+ callback(null, self);
+ });
+ }
+ });
+ }
+ });
+
+ // only pass error to callback once
+ function error (err) {
+ if(error.err) return;
+ callback(error.err = err);
+ }
+};
+
+/**
+ * Stores a file from the file system to the GridFS database.
+ *
+ * @param {String|Buffer|FileHandle} file the file to store.
+ * @param {Function} callback this will be called after this method is executed. The first parameter will be null and the the second will contain the reference to this object.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.writeFile = function (file, callback) {
+ var self = this;
+ if (typeof file === 'string') {
+ fs.open(file, 'r', 0666, function (err, fd) {
+ if(err) return callback(err);
+ self.writeFile(fd, callback);
+ });
+ return;
+ }
+
+ self.open(function (err, self) {
+ if(err) return callback(err, self);
+
+ fs.fstat(file, function (err, stats) {
+ if(err) return callback(err, self);
+
+ var offset = 0;
+ var index = 0;
+ var numberOfChunksLeft = Math.min(stats.size / self.chunkSize);
+
+ // Write a chunk
+ var writeChunk = function() {
+ fs.read(file, self.chunkSize, offset, 'binary', function(err, data, bytesRead) {
+ if(err) return callback(err, self);
+
+ offset = offset + bytesRead;
+
+ // Create a new chunk for the data
+ var chunk = new Chunk(self, {n:index++}, self.writeConcern);
+ chunk.write(data, function(err, chunk) {
+ if(err) return callback(err, self);
+
+ chunk.save(function(err, result) {
+ if(err) return callback(err, self);
+
+ self.position = self.position + data.length;
+
+ // Point to current chunk
+ self.currentChunk = chunk;
+
+ if(offset >= stats.size) {
+ fs.close(file);
+ self.close(function(err, result) {
+ if(err) return callback(err, self);
+ return callback(null, self);
+ });
+ } else {
+ return processor(writeChunk);
+ }
+ });
+ });
+ });
+ }
+
+ // Process the first write
+ processor(writeChunk);
+ });
+ });
+};
+
+/**
+ * Writes some data. This method will work properly only if initialized with mode
+ * "w" or "w+".
+ *
+ * @param string {string} The data to write.
+ * @param close {boolean=false} opt_argument Closes this file after writing if
+ * true.
+ * @param callback {function(*, GridStore)} This will be called after executing
+ * this method. The first parameter will contain null and the second one
+ * will contain a reference to this object.
+ *
+ * @ignore
+ * @api private
+ */
+var writeBuffer = function(self, buffer, close, callback) {
+ if(typeof close === "function") { callback = close; close = null; }
+ var finalClose = (close == null) ? false : close;
+
+ if(self.mode[0] != "w") {
+ callback(new Error((self.referenceBy == REFERENCE_BY_ID ? self.toHexString() : self.filename) + " not opened for writing"), null);
+ } else {
+ if(self.currentChunk.position + buffer.length >= self.chunkSize) {
+ // Write out the current Chunk and then keep writing until we have less data left than a chunkSize left
+ // to a new chunk (recursively)
+ var previousChunkNumber = self.currentChunk.chunkNumber;
+ var leftOverDataSize = self.chunkSize - self.currentChunk.position;
+ var firstChunkData = buffer.slice(0, leftOverDataSize);
+ var leftOverData = buffer.slice(leftOverDataSize);
+ // A list of chunks to write out
+ var chunksToWrite = [self.currentChunk.write(firstChunkData)];
+ // If we have more data left than the chunk size let's keep writing new chunks
+ while(leftOverData.length >= self.chunkSize) {
+ // Create a new chunk and write to it
+ var newChunk = new Chunk(self, {'n': (previousChunkNumber + 1)}, self.writeConcern);
+ var firstChunkData = leftOverData.slice(0, self.chunkSize);
+ leftOverData = leftOverData.slice(self.chunkSize);
+ // Update chunk number
+ previousChunkNumber = previousChunkNumber + 1;
+ // Write data
+ newChunk.write(firstChunkData);
+ // Push chunk to save list
+ chunksToWrite.push(newChunk);
+ }
+
+ // Set current chunk with remaining data
+ self.currentChunk = new Chunk(self, {'n': (previousChunkNumber + 1)}, self.writeConcern);
+ // If we have left over data write it
+ if(leftOverData.length > 0) self.currentChunk.write(leftOverData);
+
+ // Update the position for the gridstore
+ self.position = self.position + buffer.length;
+ // Total number of chunks to write
+ var numberOfChunksToWrite = chunksToWrite.length;
+ // Write out all the chunks and then return
+ for(var i = 0; i < chunksToWrite.length; i++) {
+ var chunk = chunksToWrite[i];
+ chunk.save(function(err, result) {
+ if(err) return callback(err);
+
+ numberOfChunksToWrite = numberOfChunksToWrite - 1;
+
+ if(numberOfChunksToWrite <= 0) {
+ return callback(null, self);
+ }
+ })
+ }
+ } else {
+ // Update the position for the gridstore
+ self.position = self.position + buffer.length;
+ // We have less data than the chunk size just write it and callback
+ self.currentChunk.write(buffer);
+ callback(null, self);
+ }
+ }
+};
+
+/**
+ * Creates a mongoDB object representation of this object.
+ *
+ * @param callback {function(object)} This will be called after executing this
+ * method. The object will be passed to the first parameter and will have
+ * the structure:
+ *
+ *
+ * {
+ * '_id' : , // {number} id for this file
+ * 'filename' : , // {string} name for this file
+ * 'contentType' : , // {string} mime type for this file
+ * 'length' : , // {number} size of this file?
+ * 'chunksize' : , // {number} chunk size used by this file
+ * 'uploadDate' : , // {Date}
+ * 'aliases' : , // {array of string}
+ * 'metadata' : , // {string}
+ * }
+ *
+ *
+ * @ignore
+ * @api private
+ */
+var buildMongoObject = function(self, callback) {
+ // // Keeps the final chunk number
+ // var chunkNumber = 0;
+ // var previousChunkSize = 0;
+ // // Get the correct chunk Number, if we have an empty chunk return the previous chunk number
+ // if(null != self.currentChunk && self.currentChunk.chunkNumber > 0 && self.currentChunk.position == 0) {
+ // chunkNumber = self.currentChunk.chunkNumber - 1;
+ // } else {
+ // chunkNumber = self.currentChunk.chunkNumber;
+ // previousChunkSize = self.currentChunk.position;
+ // }
+
+ // // Calcuate the length
+ // var length = self.currentChunk != null ? (chunkNumber * self.chunkSize + previousChunkSize) : 0;
+ var mongoObject = {
+ '_id': self.fileId,
+ 'filename': self.filename,
+ 'contentType': self.contentType,
+ 'length': self.position ? self.position : 0,
+ 'chunkSize': self.chunkSize,
+ 'uploadDate': self.uploadDate,
+ 'aliases': self.aliases,
+ 'metadata': self.metadata
+ };
+
+ var md5Command = {filemd5:self.fileId, root:self.root};
+ self.db.command(md5Command, function(err, results) {
+ mongoObject.md5 = results.md5;
+ callback(mongoObject);
+ });
+};
+
+/**
+ * Saves this file to the database. This will overwrite the old entry if it
+ * already exists. This will work properly only if mode was initialized to
+ * "w" or "w+".
+ *
+ * @param {Function} callback this will be called after executing this method. Passes an **{Error}** object to the first parameter and null to the second if an error occured. Otherwise, passes null to the first and a reference to this object to the second.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.close = function(callback) {
+ var self = this;
+
+ if(self.mode[0] == "w") {
+ if(self.currentChunk != null && self.currentChunk.position > 0) {
+ self.currentChunk.save(function(err, chunk) {
+ if(err && typeof callback == 'function') return callback(err);
+
+ self.collection(function(err, files) {
+ if(err && typeof callback == 'function') return callback(err);
+
+ // Build the mongo object
+ if(self.uploadDate != null) {
+ files.remove({'_id':self.fileId}, {safe:true}, function(err, collection) {
+ if(err && typeof callback == 'function') return callback(err);
+
+ buildMongoObject(self, function(mongoObject) {
+ files.save(mongoObject, self.writeConcern, function(err) {
+ if(typeof callback == 'function')
+ callback(err, mongoObject);
+ });
+ });
+ });
+ } else {
+ self.uploadDate = new Date();
+ buildMongoObject(self, function(mongoObject) {
+ files.save(mongoObject, self.writeConcern, function(err) {
+ if(typeof callback == 'function')
+ callback(err, mongoObject);
+ });
+ });
+ }
+ });
+ });
+ } else {
+ self.collection(function(err, files) {
+ if(err && typeof callback == 'function') return callback(err);
+
+ self.uploadDate = new Date();
+ buildMongoObject(self, function(mongoObject) {
+ files.save(mongoObject, self.writeConcern, function(err) {
+ if(typeof callback == 'function')
+ callback(err, mongoObject);
+ });
+ });
+ });
+ }
+ } else if(self.mode[0] == "r") {
+ if(typeof callback == 'function')
+ callback(null, null);
+ } else {
+ if(typeof callback == 'function')
+ callback(new Error("Illegal mode " + self.mode), null);
+ }
+};
+
+/**
+ * Gets the nth chunk of this file.
+ *
+ * @param chunkNumber {number} The nth chunk to retrieve.
+ * @param callback {function(*, Chunk|object)} This will be called after
+ * executing this method. null will be passed to the first parameter while
+ * a new {@link Chunk} instance will be passed to the second parameter if
+ * the chunk was found or an empty object {} if not.
+ *
+ * @ignore
+ * @api private
+ */
+var nthChunk = function(self, chunkNumber, callback) {
+ self.chunkCollection(function(err, collection) {
+ if(err) return callback(err);
+
+ collection.find({'files_id':self.fileId, 'n':chunkNumber}, {readPreference: self.readPreference}, function(err, cursor) {
+ if(err) return callback(err);
+
+ cursor.nextObject(function(err, chunk) {
+ if(err) return callback(err);
+
+ var finalChunk = chunk == null ? {} : chunk;
+ callback(null, new Chunk(self, finalChunk, self.writeConcern));
+ });
+ });
+ });
+};
+
+/**
+ *
+ * @ignore
+ * @api private
+ */
+GridStore.prototype._nthChunk = function(chunkNumber, callback) {
+ nthChunk(this, chunkNumber, callback);
+}
+
+/**
+ * @return {Number} The last chunk number of this file.
+ *
+ * @ignore
+ * @api private
+ */
+var lastChunkNumber = function(self) {
+ return Math.floor(self.length/self.chunkSize);
+};
+
+/**
+ * Retrieve this file's chunks collection.
+ *
+ * @param {Function} callback this will be called after executing this method. An exception object will be passed to the first parameter when an error occured or null otherwise. A new **{Collection}** object will be passed to the second parameter if no error occured.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.chunkCollection = function(callback) {
+ this.db.collection((this.root + ".chunks"), callback);
+};
+
+/**
+ * Deletes all the chunks of this file in the database.
+ *
+ * @param callback {function(*, boolean)} This will be called after this method
+ * executes. Passes null to the first and true to the second argument.
+ *
+ * @ignore
+ * @api private
+ */
+var deleteChunks = function(self, callback) {
+ if(self.fileId != null) {
+ self.chunkCollection(function(err, collection) {
+ if(err) return callback(err, false);
+ collection.remove({'files_id':self.fileId}, {safe:true}, function(err, result) {
+ if(err) return callback(err, false);
+ callback(null, true);
+ });
+ });
+ } else {
+ callback(null, true);
+ }
+};
+
+/**
+ * Deletes all the chunks of this file in the database.
+ *
+ * @param {Function} callback this will be called after this method executes. Passes null to the first and true to the second argument.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.unlink = function(callback) {
+ var self = this;
+ deleteChunks(this, function(err) {
+ if(err!==null) {
+ err.message = "at deleteChunks: " + err.message;
+ return callback(err);
+ }
+
+ self.collection(function(err, collection) {
+ if(err!==null) {
+ err.message = "at collection: " + err.message;
+ return callback(err);
+ }
+
+ collection.remove({'_id':self.fileId}, {safe:true}, function(err) {
+ callback(err, self);
+ });
+ });
+ });
+};
+
+/**
+ * Retrieves the file collection associated with this object.
+ *
+ * @param {Function} callback this will be called after executing this method. An exception object will be passed to the first parameter when an error occured or null otherwise. A new **{Collection}** object will be passed to the second parameter if no error occured.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.collection = function(callback) {
+ this.db.collection(this.root + ".files", callback);
+};
+
+/**
+ * Reads the data of this file.
+ *
+ * @param {String} [separator] the character to be recognized as the newline separator.
+ * @param {Function} callback This will be called after this method is executed. The first parameter will be null and the second parameter will contain an array of strings representing the entire data, each element representing a line including the separator character.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.readlines = function(separator, callback) {
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ separator = args.length ? args.shift() : "\n";
+
+ this.read(function(err, data) {
+ if(err) return callback(err);
+
+ var items = data.toString().split(separator);
+ items = items.length > 0 ? items.splice(0, items.length - 1) : [];
+ for(var i = 0; i < items.length; i++) {
+ items[i] = items[i] + separator;
+ }
+
+ callback(null, items);
+ });
+};
+
+/**
+ * Deletes all the chunks of this file in the database if mode was set to "w" or
+ * "w+" and resets the read/write head to the initial position.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.rewind = function(callback) {
+ var self = this;
+
+ if(this.currentChunk.chunkNumber != 0) {
+ if(this.mode[0] == "w") {
+ deleteChunks(self, function(err, gridStore) {
+ if(err) return callback(err);
+ self.currentChunk = new Chunk(self, {'n': 0}, self.writeConcern);
+ self.position = 0;
+ callback(null, self);
+ });
+ } else {
+ self.currentChunk(0, function(err, chunk) {
+ if(err) return callback(err);
+ self.currentChunk = chunk;
+ self.currentChunk.rewind();
+ self.position = 0;
+ callback(null, self);
+ });
+ }
+ } else {
+ self.currentChunk.rewind();
+ self.position = 0;
+ callback(null, self);
+ }
+};
+
+/**
+ * Retrieves the contents of this file and advances the read/write head. Works with Buffers only.
+ *
+ * There are 3 signatures for this method:
+ *
+ * (callback)
+ * (length, callback)
+ * (length, buffer, callback)
+ *
+ * @param {Number} [length] the number of characters to read. Reads all the characters from the read/write head to the EOF if not specified.
+ * @param {String|Buffer} [buffer] a string to hold temporary data. This is used for storing the string data read so far when recursively calling this method.
+ * @param {Function} callback this will be called after this method is executed. null will be passed to the first parameter and a string containing the contents of the buffer concatenated with the contents read from this file will be passed to the second.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.read = function(length, buffer, callback) {
+ var self = this;
+
+ var args = Array.prototype.slice.call(arguments, 0);
+ callback = args.pop();
+ length = args.length ? args.shift() : null;
+ buffer = args.length ? args.shift() : null;
+
+ // The data is a c-terminated string and thus the length - 1
+ var finalLength = length == null ? self.length - self.position : length;
+ var finalBuffer = buffer == null ? new Buffer(finalLength) : buffer;
+ // Add a index to buffer to keep track of writing position or apply current index
+ finalBuffer._index = buffer != null && buffer._index != null ? buffer._index : 0;
+
+ if((self.currentChunk.length() - self.currentChunk.position + finalBuffer._index) >= finalLength) {
+ var slice = self.currentChunk.readSlice(finalLength - finalBuffer._index);
+ // Copy content to final buffer
+ slice.copy(finalBuffer, finalBuffer._index);
+ // Update internal position
+ self.position = self.position + finalBuffer.length;
+ // Check if we don't have a file at all
+ if(finalLength == 0 && finalBuffer.length == 0) return callback(new Error("File does not exist"), null);
+ // Else return data
+ callback(null, finalBuffer);
+ } else {
+ var slice = self.currentChunk.readSlice(self.currentChunk.length() - self.currentChunk.position);
+ // Copy content to final buffer
+ slice.copy(finalBuffer, finalBuffer._index);
+ // Update index position
+ finalBuffer._index += slice.length;
+
+ // Load next chunk and read more
+ nthChunk(self, self.currentChunk.chunkNumber + 1, function(err, chunk) {
+ if(err) return callback(err);
+
+ if(chunk.length() > 0) {
+ self.currentChunk = chunk;
+ self.read(length, finalBuffer, callback);
+ } else {
+ if (finalBuffer._index > 0) {
+ callback(null, finalBuffer)
+ } else {
+ callback(new Error("no chunks found for file, possibly corrupt"), null);
+ }
+ }
+ });
+ }
+}
+
+/**
+ * Retrieves the position of the read/write head of this file.
+ *
+ * @param {Function} callback This gets called after this method terminates. null is passed to the first parameter and the position is passed to the second.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.tell = function(callback) {
+ callback(null, this.position);
+};
+
+/**
+ * Moves the read/write head to a new location.
+ *
+ * There are 3 signatures for this method
+ *
+ * Seek Location Modes
+ * - **GridStore.IO_SEEK_SET**, **(default)** set the position from the start of the file.
+ * - **GridStore.IO_SEEK_CUR**, set the position from the current position in the file.
+ * - **GridStore.IO_SEEK_END**, set the position from the end of the file.
+ *
+ * @param {Number} [position] the position to seek to
+ * @param {Number} [seekLocation] seek mode. Use one of the Seek Location modes.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.seek = function(position, seekLocation, callback) {
+ var self = this;
+
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ seekLocation = args.length ? args.shift() : null;
+
+ var seekLocationFinal = seekLocation == null ? exports.GridStore.IO_SEEK_SET : seekLocation;
+ var finalPosition = position;
+ var targetPosition = 0;
+
+ // Calculate the position
+ if(seekLocationFinal == exports.GridStore.IO_SEEK_CUR) {
+ targetPosition = self.position + finalPosition;
+ } else if(seekLocationFinal == exports.GridStore.IO_SEEK_END) {
+ targetPosition = self.length + finalPosition;
+ } else {
+ targetPosition = finalPosition;
+ }
+
+ // Get the chunk
+ var newChunkNumber = Math.floor(targetPosition/self.chunkSize);
+ if(newChunkNumber != self.currentChunk.chunkNumber) {
+ var seekChunk = function() {
+ nthChunk(self, newChunkNumber, function(err, chunk) {
+ self.currentChunk = chunk;
+ self.position = targetPosition;
+ self.currentChunk.position = (self.position % self.chunkSize);
+ callback(err, self);
+ });
+ };
+
+ if(self.mode[0] == 'w') {
+ self.currentChunk.save(function(err) {
+ if(err) return callback(err);
+ seekChunk();
+ });
+ } else {
+ seekChunk();
+ }
+ } else {
+ self.position = targetPosition;
+ self.currentChunk.position = (self.position % self.chunkSize);
+ callback(null, self);
+ }
+};
+
+/**
+ * Verify if the file is at EOF.
+ *
+ * @return {Boolean} true if the read/write head is at the end of this file.
+ * @api public
+ */
+GridStore.prototype.eof = function() {
+ return this.position == this.length ? true : false;
+};
+
+/**
+ * Retrieves a single character from this file.
+ *
+ * @param {Function} callback this gets called after this method is executed. Passes null to the first parameter and the character read to the second or null to the second if the read/write head is at the end of the file.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.getc = function(callback) {
+ var self = this;
+
+ if(self.eof()) {
+ callback(null, null);
+ } else if(self.currentChunk.eof()) {
+ nthChunk(self, self.currentChunk.chunkNumber + 1, function(err, chunk) {
+ self.currentChunk = chunk;
+ self.position = self.position + 1;
+ callback(err, self.currentChunk.getc());
+ });
+ } else {
+ self.position = self.position + 1;
+ callback(null, self.currentChunk.getc());
+ }
+};
+
+/**
+ * Writes a string to the file with a newline character appended at the end if
+ * the given string does not have one.
+ *
+ * @param {String} string the string to write.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.puts = function(string, callback) {
+ var finalString = string.match(/\n$/) == null ? string + "\n" : string;
+ this.write(finalString, callback);
+};
+
+/**
+ * Returns read stream based on this GridStore file
+ *
+ * Events
+ * - **data** {function(item) {}} the data event triggers when a document is ready.
+ * - **end** {function() {}} the end event triggers when there is no more documents available.
+ * - **close** {function() {}} the close event triggers when the stream is closed.
+ * - **error** {function(err) {}} the error event triggers if an error happens.
+ *
+ * @param {Boolean} autoclose if true current GridStore will be closed when EOF and 'close' event will be fired
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.stream = function(autoclose) {
+ return new ReadStream(autoclose, this);
+};
+
+/**
+* The collection to be used for holding the files and chunks collection.
+*
+* @classconstant DEFAULT_ROOT_COLLECTION
+**/
+GridStore.DEFAULT_ROOT_COLLECTION = 'fs';
+
+/**
+* Default file mime type
+*
+* @classconstant DEFAULT_CONTENT_TYPE
+**/
+GridStore.DEFAULT_CONTENT_TYPE = 'binary/octet-stream';
+
+/**
+* Seek mode where the given length is absolute.
+*
+* @classconstant IO_SEEK_SET
+**/
+GridStore.IO_SEEK_SET = 0;
+
+/**
+* Seek mode where the given length is an offset to the current read/write head.
+*
+* @classconstant IO_SEEK_CUR
+**/
+GridStore.IO_SEEK_CUR = 1;
+
+/**
+* Seek mode where the given length is an offset to the end of the file.
+*
+* @classconstant IO_SEEK_END
+**/
+GridStore.IO_SEEK_END = 2;
+
+/**
+ * Checks if a file exists in the database.
+ *
+ * Options
+ * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ *
+ * @param {Db} db the database to query.
+ * @param {String} name the name of the file to look for.
+ * @param {String} [rootCollection] the root collection that holds the files and chunks collection. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**.
+ * @param {Function} callback this will be called after this method executes. Passes null to the first and passes true to the second if the file exists and false otherwise.
+ * @return {null}
+ * @api public
+ */
+GridStore.exist = function(db, fileIdObject, rootCollection, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = args.pop();
+ rootCollection = args.length ? args.shift() : null;
+ options = args.length ? args.shift() : {};
+
+ // Establish read preference
+ var readPreference = options.readPreference || 'primary';
+ // Fetch collection
+ var rootCollectionFinal = rootCollection != null ? rootCollection : GridStore.DEFAULT_ROOT_COLLECTION;
+ db.collection(rootCollectionFinal + ".files", function(err, collection) {
+ if(err) return callback(err);
+
+ // Build query
+ var query = (typeof fileIdObject == 'string' || Object.prototype.toString.call(fileIdObject) == '[object RegExp]' )
+ ? {'filename':fileIdObject}
+ : {'_id':fileIdObject}; // Attempt to locate file
+
+ collection.find(query, {readPreference:readPreference}, function(err, cursor) {
+ if(err) return callback(err);
+
+ cursor.nextObject(function(err, item) {
+ if(err) return callback(err);
+ callback(null, item == null ? false : true);
+ });
+ });
+ });
+};
+
+/**
+ * Gets the list of files stored in the GridFS.
+ *
+ * @param {Db} db the database to query.
+ * @param {String} [rootCollection] the root collection that holds the files and chunks collection. Defaults to **{GridStore.DEFAULT_ROOT_COLLECTION}**.
+ * @param {Function} callback this will be called after this method executes. Passes null to the first and passes an array of strings containing the names of the files.
+ * @return {null}
+ * @api public
+ */
+GridStore.list = function(db, rootCollection, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = args.pop();
+ rootCollection = args.length ? args.shift() : null;
+ options = args.length ? args.shift() : {};
+
+ // Ensure we have correct values
+ if(rootCollection != null && typeof rootCollection == 'object') {
+ options = rootCollection;
+ rootCollection = null;
+ }
+
+ // Establish read preference
+ var readPreference = options.readPreference || 'primary';
+ // Check if we are returning by id not filename
+ var byId = options['id'] != null ? options['id'] : false;
+ // Fetch item
+ var rootCollectionFinal = rootCollection != null ? rootCollection : GridStore.DEFAULT_ROOT_COLLECTION;
+ var items = [];
+ db.collection((rootCollectionFinal + ".files"), function(err, collection) {
+ if(err) return callback(err);
+
+ collection.find({}, {readPreference:readPreference}, function(err, cursor) {
+ if(err) return callback(err);
+
+ cursor.each(function(err, item) {
+ if(item != null) {
+ items.push(byId ? item._id : item.filename);
+ } else {
+ callback(err, items);
+ }
+ });
+ });
+ });
+};
+
+/**
+ * Reads the contents of a file.
+ *
+ * This method has the following signatures
+ *
+ * (db, name, callback)
+ * (db, name, length, callback)
+ * (db, name, length, offset, callback)
+ * (db, name, length, offset, options, callback)
+ *
+ * @param {Db} db the database to query.
+ * @param {String} name the name of the file.
+ * @param {Number} [length] the size of data to read.
+ * @param {Number} [offset] the offset from the head of the file of which to start reading from.
+ * @param {Object} [options] the options for the file.
+ * @param {Function} callback this will be called after this method executes. A string with an error message will be passed to the first parameter when the length and offset combination exceeds the length of the file while an Error object will be passed if other forms of error occured, otherwise, a string is passed. The second parameter will contain the data read if successful or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+GridStore.read = function(db, name, length, offset, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = args.pop();
+ length = args.length ? args.shift() : null;
+ offset = args.length ? args.shift() : null;
+ options = args.length ? args.shift() : null;
+
+ new GridStore(db, name, "r", options).open(function(err, gridStore) {
+ if(err) return callback(err);
+ // Make sure we are not reading out of bounds
+ if(offset && offset >= gridStore.length) return callback("offset larger than size of file", null);
+ if(length && length > gridStore.length) return callback("length is larger than the size of the file", null);
+ if(offset && length && (offset + length) > gridStore.length) return callback("offset and length is larger than the size of the file", null);
+
+ if(offset != null) {
+ gridStore.seek(offset, function(err, gridStore) {
+ if(err) return callback(err);
+ gridStore.read(length, callback);
+ });
+ } else {
+ gridStore.read(length, callback);
+ }
+ });
+};
+
+/**
+ * Reads the data of this file.
+ *
+ * @param {Db} db the database to query.
+ * @param {String} name the name of the file.
+ * @param {String} [separator] the character to be recognized as the newline separator.
+ * @param {Object} [options] file options.
+ * @param {Function} callback this will be called after this method is executed. The first parameter will be null and the second parameter will contain an array of strings representing the entire data, each element representing a line including the separator character.
+ * @return {null}
+ * @api public
+ */
+GridStore.readlines = function(db, name, separator, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = args.pop();
+ separator = args.length ? args.shift() : null;
+ options = args.length ? args.shift() : null;
+
+ var finalSeperator = separator == null ? "\n" : separator;
+ new GridStore(db, name, "r", options).open(function(err, gridStore) {
+ if(err) return callback(err);
+ gridStore.readlines(finalSeperator, callback);
+ });
+};
+
+/**
+ * Deletes the chunks and metadata information of a file from GridFS.
+ *
+ * @param {Db} db the database to interact with.
+ * @param {String|Array} names the name/names of the files to delete.
+ * @param {Object} [options] the options for the files.
+ * @callback {Function} this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object.
+ * @return {null}
+ * @api public
+ */
+GridStore.unlink = function(db, names, options, callback) {
+ var self = this;
+ var args = Array.prototype.slice.call(arguments, 2);
+ callback = args.pop();
+ options = args.length ? args.shift() : null;
+
+ if(names.constructor == Array) {
+ var tc = 0;
+ for(var i = 0; i < names.length; i++) {
+ ++tc;
+ self.unlink(db, names[i], function(result) {
+ if(--tc == 0) {
+ callback(null, self);
+ }
+ });
+ }
+ } else {
+ new GridStore(db, names, "w", options).open(function(err, gridStore) {
+ if(err) return callback(err);
+ deleteChunks(gridStore, function(err, result) {
+ if(err) return callback(err);
+ gridStore.collection(function(err, collection) {
+ if(err) return callback(err);
+ collection.remove({'_id':gridStore.fileId}, {safe:true}, function(err, collection) {
+ callback(err, self);
+ });
+ });
+ });
+ });
+ }
+};
+
+/**
+ * Returns the current chunksize of the file.
+ *
+ * @field chunkSize
+ * @type {Number}
+ * @getter
+ * @setter
+ * @property return number of bytes in the current chunkSize.
+ */
+Object.defineProperty(GridStore.prototype, "chunkSize", { enumerable: true
+ , get: function () {
+ return this.internalChunkSize;
+ }
+ , set: function(value) {
+ if(!(this.mode[0] == "w" && this.position == 0 && this.uploadDate == null)) {
+ this.internalChunkSize = this.internalChunkSize;
+ } else {
+ this.internalChunkSize = value;
+ }
+ }
+});
+
+/**
+ * The md5 checksum for this file.
+ *
+ * @field md5
+ * @type {Number}
+ * @getter
+ * @setter
+ * @property return this files md5 checksum.
+ */
+Object.defineProperty(GridStore.prototype, "md5", { enumerable: true
+ , get: function () {
+ return this.internalMd5;
+ }
+});
+
+/**
+ * GridStore Streaming methods
+ * Handles the correct return of the writeable stream status
+ * @ignore
+ */
+Object.defineProperty(GridStore.prototype, "writable", { enumerable: true
+ , get: function () {
+ if(this._writeable == null) {
+ this._writeable = this.mode != null && this.mode.indexOf("w") != -1;
+ }
+ // Return the _writeable
+ return this._writeable;
+ }
+ , set: function(value) {
+ this._writeable = value;
+ }
+});
+
+/**
+ * Handles the correct return of the readable stream status
+ * @ignore
+ */
+Object.defineProperty(GridStore.prototype, "readable", { enumerable: true
+ , get: function () {
+ if(this._readable == null) {
+ this._readable = this.mode != null && this.mode.indexOf("r") != -1;
+ }
+ return this._readable;
+ }
+ , set: function(value) {
+ this._readable = value;
+ }
+});
+
+GridStore.prototype.paused;
+
+/**
+ * Handles the correct setting of encoding for the stream
+ * @ignore
+ */
+GridStore.prototype.setEncoding = fs.ReadStream.prototype.setEncoding;
+
+/**
+ * Handles the end events
+ * @ignore
+ */
+GridStore.prototype.end = function end(data) {
+ var self = this;
+ // allow queued data to write before closing
+ if(!this.writable) return;
+ this.writable = false;
+
+ if(data) {
+ this._q.push(data);
+ }
+
+ this.on('drain', function () {
+ self.close(function (err) {
+ if (err) return _error(self, err);
+ self.emit('close');
+ });
+ });
+
+ _flush(self);
+}
+
+/**
+ * Handles the normal writes to gridstore
+ * @ignore
+ */
+var _writeNormal = function(self, data, close, callback) {
+ // If we have a buffer write it using the writeBuffer method
+ if(Buffer.isBuffer(data)) {
+ return writeBuffer(self, data, close, callback);
+ } else {
+ // Wrap the string in a buffer and write
+ return writeBuffer(self, new Buffer(data, 'binary'), close, callback);
+ }
+}
+
+/**
+ * Writes some data. This method will work properly only if initialized with mode "w" or "w+".
+ *
+ * @param {String|Buffer} data the data to write.
+ * @param {Boolean} [close] closes this file after writing if set to true.
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain null and the second one will contain a reference to this object.
+ * @return {null}
+ * @api public
+ */
+GridStore.prototype.write = function write(data, close, callback) {
+ // If it's a normal write delegate the call
+ if(typeof close == 'function' || typeof callback == 'function') {
+ return _writeNormal(this, data, close, callback);
+ }
+
+ // Otherwise it's a stream write
+ var self = this;
+ if (!this.writable) {
+ throw new Error('GridWriteStream is not writable');
+ }
+
+ // queue data until we open.
+ if (!this._opened) {
+ // Set up a queue to save data until gridstore object is ready
+ this._q = [];
+ _openStream(self);
+ this._q.push(data);
+ return false;
+ }
+
+ // Push data to queue
+ this._q.push(data);
+ _flush(this);
+ // Return write successful
+ return true;
+}
+
+/**
+ * Handles the destroy part of a stream
+ * @ignore
+ */
+GridStore.prototype.destroy = function destroy() {
+ // close and do not emit any more events. queued data is not sent.
+ if(!this.writable) return;
+ this.readable = false;
+ if(this.writable) {
+ this.writable = false;
+ this._q.length = 0;
+ this.emit('close');
+ }
+}
+
+/**
+ * Handles the destroySoon part of a stream
+ * @ignore
+ */
+GridStore.prototype.destroySoon = function destroySoon() {
+ // as soon as write queue is drained, destroy.
+ // may call destroy immediately if no data is queued.
+ if(!this._q.length) {
+ return this.destroy();
+ }
+ this._destroying = true;
+}
+
+/**
+ * Handles the pipe part of the stream
+ * @ignore
+ */
+GridStore.prototype.pipe = function(destination, options) {
+ var self = this;
+ // Open the gridstore
+ this.open(function(err, result) {
+ if(err) _errorRead(self, err);
+ if(!self.readable) return;
+ // Set up the pipe
+ self._pipe(destination, options);
+ // Emit the stream is open
+ self.emit('open');
+ // Read from the stream
+ _read(self);
+ })
+}
+
+/**
+ * Internal module methods
+ * @ignore
+ */
+var _read = function _read(self) {
+ if (!self.readable || self.paused || self.reading) {
+ return;
+ }
+
+ self.reading = true;
+ var stream = self._stream = self.stream();
+ stream.paused = self.paused;
+
+ stream.on('data', function (data) {
+ if (self._decoder) {
+ var str = self._decoder.write(data);
+ if (str.length) self.emit('data', str);
+ } else {
+ self.emit('data', data);
+ }
+ });
+
+ stream.on('end', function (data) {
+ self.emit('end', data);
+ });
+
+ stream.on('error', function (data) {
+ _errorRead(self, data);
+ });
+
+ stream.on('close', function (data) {
+ self.emit('close', data);
+ });
+
+ self.pause = function () {
+ // native doesn't always pause.
+ // bypass its pause() method to hack it
+ self.paused = stream.paused = true;
+ }
+
+ self.resume = function () {
+ if(!self.paused) return;
+
+ self.paused = false;
+ stream.resume();
+ self.readable = stream.readable;
+ }
+
+ self.destroy = function () {
+ self.readable = false;
+ stream.destroy();
+ }
+}
+
+/**
+ * pause
+ * @ignore
+ */
+GridStore.prototype.pause = function pause () {
+ // Overridden when the GridStore opens.
+ this.paused = true;
+}
+
+/**
+ * resume
+ * @ignore
+ */
+GridStore.prototype.resume = function resume () {
+ // Overridden when the GridStore opens.
+ this.paused = false;
+}
+
+/**
+ * Internal module methods
+ * @ignore
+ */
+var _flush = function _flush(self, _force) {
+ if (!self._opened) return;
+ if (!_force && self._flushing) return;
+ self._flushing = true;
+
+ // write the entire q to gridfs
+ if (!self._q.length) {
+ self._flushing = false;
+ self.emit('drain');
+
+ if(self._destroying) {
+ self.destroy();
+ }
+ return;
+ }
+
+ self.write(self._q.shift(), function (err, store) {
+ if (err) return _error(self, err);
+ self.emit('progress', store.position);
+ _flush(self, true);
+ });
+}
+
+var _openStream = function _openStream (self) {
+ if(self._opening == true) return;
+ self._opening = true;
+
+ // Open the store
+ self.open(function (err, gridstore) {
+ if (err) return _error(self, err);
+ self._opened = true;
+ self.emit('open');
+ _flush(self);
+ });
+}
+
+var _error = function _error(self, err) {
+ self.destroy();
+ self.emit('error', err);
+}
+
+var _errorRead = function _errorRead (self, err) {
+ self.readable = false;
+ self.emit('error', err);
+}
+
+/**
+ * @ignore
+ */
+var _hasWriteConcern = function(errorOptions) {
+ return errorOptions == true
+ || errorOptions.w > 0
+ || errorOptions.w == 'majority'
+ || errorOptions.j == true
+ || errorOptions.journal == true
+ || errorOptions.fsync == true
+}
+
+/**
+ * @ignore
+ */
+var _setWriteConcernHash = function(options) {
+ var finalOptions = {};
+ if(options.w != null) finalOptions.w = options.w;
+ if(options.journal == true) finalOptions.j = options.journal;
+ if(options.j == true) finalOptions.j = options.j;
+ if(options.fsync == true) finalOptions.fsync = options.fsync;
+ if(options.wtimeout != null) finalOptions.wtimeout = options.wtimeout;
+ return finalOptions;
+}
+
+/**
+ * @ignore
+ */
+var _getWriteConcern = function(self, options, callback) {
+ // Final options
+ var finalOptions = {w:1};
+ options = options || {};
+ // Local options verification
+ if(options.w != null || typeof options.j == 'boolean' || typeof options.journal == 'boolean' || typeof options.fsync == 'boolean') {
+ finalOptions = _setWriteConcernHash(options);
+ } else if(typeof options.safe == "boolean") {
+ finalOptions = {w: (options.safe ? 1 : 0)};
+ } else if(options.safe != null && typeof options.safe == 'object') {
+ finalOptions = _setWriteConcernHash(options.safe);
+ } else if(self.db.safe.w != null || typeof self.db.safe.j == 'boolean' || typeof self.db.safe.journal == 'boolean' || typeof self.db.safe.fsync == 'boolean') {
+ finalOptions = _setWriteConcernHash(self.db.safe);
+ } else if(self.db.options.w != null || typeof self.db.options.j == 'boolean' || typeof self.db.options.journal == 'boolean' || typeof self.db.options.fsync == 'boolean') {
+ finalOptions = _setWriteConcernHash(self.db.options);
+ } else if(typeof self.db.safe == "boolean") {
+ finalOptions = {w: (self.db.safe ? 1 : 0)};
+ }
+
+ // Ensure we don't have an invalid combination of write concerns
+ if(finalOptions.w < 1
+ && (finalOptions.journal == true || finalOptions.j == true || finalOptions.fsync == true)) throw new Error("No acknowlegement using w < 1 cannot be combined with journal:true or fsync:true");
+
+ // Return the options
+ return finalOptions;
+}
+
+/**
+ * @ignore
+ * @api private
+ */
+exports.GridStore = GridStore;
diff --git a/node_modules/mongodb/lib/mongodb/gridfs/readstream.js b/node_modules/mongodb/lib/mongodb/gridfs/readstream.js
new file mode 100644
index 0000000..8ff9973
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/gridfs/readstream.js
@@ -0,0 +1,193 @@
+var Stream = require('stream').Stream,
+ timers = require('timers'),
+ util = require('util');
+
+// Set processor, setImmediate if 0.10 otherwise nextTick
+var processor = timers.setImmediate ? timers.setImmediate : process.nextTick;
+processor = process.nextTick
+
+/**
+ * ReadStream
+ *
+ * Returns a stream interface for the **file**.
+ *
+ * Events
+ * - **data** {function(item) {}} the data event triggers when a document is ready.
+ * - **end** {function() {}} the end event triggers when there is no more documents available.
+ * - **close** {function() {}} the close event triggers when the stream is closed.
+ * - **error** {function(err) {}} the error event triggers if an error happens.
+ *
+ * @class Represents a GridFS File Stream.
+ * @param {Boolean} autoclose automatically close file when the stream reaches the end.
+ * @param {GridStore} cursor a cursor object that the stream wraps.
+ * @return {ReadStream}
+ */
+function ReadStream(autoclose, gstore) {
+ if (!(this instanceof ReadStream)) return new ReadStream(autoclose, gstore);
+ Stream.call(this);
+
+ this.autoclose = !!autoclose;
+ this.gstore = gstore;
+
+ this.finalLength = gstore.length - gstore.position;
+ this.completedLength = 0;
+ this.currentChunkNumber = gstore.currentChunk.chunkNumber;
+
+ this.paused = false;
+ this.readable = true;
+ this.pendingChunk = null;
+ this.executing = false;
+
+ // Calculate the number of chunks
+ this.numberOfChunks = Math.ceil(gstore.length/gstore.chunkSize);
+
+ // This seek start position inside the current chunk
+ this.seekStartPosition = gstore.position - (this.currentChunkNumber * gstore.chunkSize);
+
+ var self = this;
+ processor(function() {
+ self._execute();
+ });
+};
+
+/**
+ * Inherit from Stream
+ * @ignore
+ * @api private
+ */
+ReadStream.prototype.__proto__ = Stream.prototype;
+
+/**
+ * Flag stating whether or not this stream is readable.
+ */
+ReadStream.prototype.readable;
+
+/**
+ * Flag stating whether or not this stream is paused.
+ */
+ReadStream.prototype.paused;
+
+/**
+ * @ignore
+ * @api private
+ */
+ReadStream.prototype._execute = function() {
+ if(this.paused === true || this.readable === false) {
+ return;
+ }
+
+ var gstore = this.gstore;
+ var self = this;
+ // Set that we are executing
+ this.executing = true;
+
+ var last = false;
+ var toRead = 0;
+
+ if(gstore.currentChunk.chunkNumber >= (this.numberOfChunks - 1)) {
+ self.executing = false;
+ last = true;
+ }
+
+ // Data setup
+ var data = null;
+
+ // Read a slice (with seek set if none)
+ if(this.seekStartPosition > 0 && (gstore.currentChunk.length() - this.seekStartPosition) > 0) {
+ data = gstore.currentChunk.readSlice(gstore.currentChunk.length() - this.seekStartPosition);
+ this.seekStartPosition = 0;
+ } else {
+ data = gstore.currentChunk.readSlice(gstore.currentChunk.length());
+ }
+
+ // Return the data
+ if(data != null && gstore.currentChunk.chunkNumber == self.currentChunkNumber) {
+ self.currentChunkNumber = self.currentChunkNumber + 1;
+ self.completedLength += data.length;
+ self.pendingChunk = null;
+ self.emit("data", data);
+ }
+
+ if(last === true) {
+ self.readable = false;
+ self.emit("end");
+
+ if(self.autoclose === true) {
+ if(gstore.mode[0] == "w") {
+ gstore.close(function(err, doc) {
+ if (err) {
+ self.emit("error", err);
+ return;
+ }
+ self.readable = false;
+ self.emit("close", doc);
+ });
+ } else {
+ self.readable = false;
+ self.emit("close");
+ }
+ }
+ } else {
+ gstore._nthChunk(gstore.currentChunk.chunkNumber + 1, function(err, chunk) {
+ if(err) {
+ self.readable = false;
+ self.emit("error", err);
+ self.executing = false;
+ return;
+ }
+
+ self.pendingChunk = chunk;
+ if(self.paused === true) {
+ self.executing = false;
+ return;
+ }
+
+ gstore.currentChunk = self.pendingChunk;
+ self._execute();
+ });
+ }
+};
+
+/**
+ * Pauses this stream, then no farther events will be fired.
+ *
+ * @ignore
+ * @api public
+ */
+ReadStream.prototype.pause = function() {
+ if(!this.executing) {
+ this.paused = true;
+ }
+};
+
+/**
+ * Destroys the stream, then no farther events will be fired.
+ *
+ * @ignore
+ * @api public
+ */
+ReadStream.prototype.destroy = function() {
+ this.readable = false;
+ // Emit close event
+ this.emit("close");
+};
+
+/**
+ * Resumes this stream.
+ *
+ * @ignore
+ * @api public
+ */
+ReadStream.prototype.resume = function() {
+ if(this.paused === false || !this.readable) {
+ return;
+ }
+
+ this.paused = false;
+ var self = this;
+ processor(function() {
+ self._execute();
+ });
+};
+
+exports.ReadStream = ReadStream;
diff --git a/node_modules/mongodb/lib/mongodb/index.js b/node_modules/mongodb/lib/mongodb/index.js
new file mode 100644
index 0000000..b2fdadf
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/index.js
@@ -0,0 +1,66 @@
+try {
+ exports.BSONPure = require('bson').BSONPure;
+ exports.BSONNative = require('bson').BSONNative;
+} catch(err) {
+ // do nothing
+}
+
+[ 'commands/base_command'
+ , 'admin'
+ , 'collection'
+ , 'connection/read_preference'
+ , 'connection/connection'
+ , 'connection/server'
+ , 'connection/mongos'
+ , 'connection/repl_set/repl_set'
+ , 'mongo_client'
+ , 'cursor'
+ , 'db'
+ , 'mongo_client'
+ , 'gridfs/grid'
+ , 'gridfs/chunk'
+ , 'gridfs/gridstore'].forEach(function (path) {
+ var module = require('./' + path);
+ for (var i in module) {
+ exports[i] = module[i];
+ }
+});
+
+// backwards compat
+exports.ReplSetServers = exports.ReplSet;
+// Add BSON Classes
+exports.Binary = require('bson').Binary;
+exports.Code = require('bson').Code;
+exports.DBRef = require('bson').DBRef;
+exports.Double = require('bson').Double;
+exports.Long = require('bson').Long;
+exports.MinKey = require('bson').MinKey;
+exports.MaxKey = require('bson').MaxKey;
+exports.ObjectID = require('bson').ObjectID;
+exports.Symbol = require('bson').Symbol;
+exports.Timestamp = require('bson').Timestamp;
+// Add BSON Parser
+exports.BSON = require('bson').BSONPure.BSON;
+
+// Get the Db object
+var Db = require('./db').Db;
+// Set up the connect function
+var connect = Db.connect;
+var obj = connect;
+// Map all values to the exports value
+for(var name in exports) {
+ obj[name] = exports[name];
+}
+
+// Add the pure and native backward compatible functions
+exports.pure = exports.native = function() {
+ return obj;
+}
+
+// Map all values to the exports value
+for(var name in exports) {
+ connect[name] = exports[name];
+}
+
+// Set our exports to be the connect function
+module.exports = connect;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/mongo_client.js b/node_modules/mongodb/lib/mongodb/mongo_client.js
new file mode 100644
index 0000000..1593fd7
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/mongo_client.js
@@ -0,0 +1,369 @@
+var Db = require('./db').Db
+ , Server = require('./connection/server').Server
+ , Mongos = require('./connection/mongos').Mongos
+ , ReplSet = require('./connection/repl_set/repl_set').ReplSet
+ , ReadPreference = require('./connection/read_preference').ReadPreference
+ , inherits = require('util').inherits
+ , EventEmitter = require('events').EventEmitter
+ , parse = require('./connection/url_parser').parse;
+
+/**
+ * Create a new MongoClient instance.
+ *
+ * Options
+ * - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
+ * - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
+ * - **fsync**, (Boolean, default:false) write waits for fsync before returning
+ * - **journal**, (Boolean, default:false) write waits for journal sync before returning
+ * - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
+ * - **native_parser** {Boolean, default:false}, use c++ bson parser.
+ * - **forceServerObjectId** {Boolean, default:false}, force server to create _id fields instead of client.
+ * - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation.
+ * - **serializeFunctions** {Boolean, default:false}, serialize functions.
+ * - **raw** {Boolean, default:false}, peform operations using raw bson buffers.
+ * - **recordQueryStats** {Boolean, default:false}, record query statistics during execution.
+ * - **retryMiliSeconds** {Number, default:5000}, number of miliseconds between retries.
+ * - **numberOfRetries** {Number, default:5}, number of retries off connection.
+ *
+ * Deprecated Options
+ * - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
+ *
+ * @class Represents a MongoClient
+ * @param {Object} serverConfig server config object.
+ * @param {Object} [options] additional options for the collection.
+ */
+function MongoClient(serverConfig, options) {
+ if(serverConfig != null) {
+ options = options == null ? {} : options;
+ // If no write concern is set set the default to w:1
+ if(options != null && !options.journal && !options.w && !options.fsync) {
+ options.w = 1;
+ }
+
+ // The internal db instance we are wrapping
+ this._db = new Db('test', serverConfig, options);
+ }
+}
+
+/**
+ * @ignore
+ */
+inherits(MongoClient, EventEmitter);
+
+/**
+ * Connect to MongoDB using a url as documented at
+ *
+ * docs.mongodb.org/manual/reference/connection-string/
+ *
+ * Options
+ * - **uri_decode_auth** {Boolean, default:false} uri decode the user name and password for authentication
+ * - **db** {Object, default: null} a hash off options to set on the db object, see **Db constructor**
+ * - **server** {Object, default: null} a hash off options to set on the server objects, see **Server** constructor**
+ * - **replSet** {Object, default: null} a hash off options to set on the replSet object, see **ReplSet** constructor**
+ * - **mongos** {Object, default: null} a hash off options to set on the mongos object, see **Mongos** constructor**
+ *
+ * @param {String} url connection url for MongoDB.
+ * @param {Object} [options] optional options for insert command
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the initialized db object or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+MongoClient.prototype.connect = function(url, options, callback) {
+ var self = this;
+
+ if(typeof options == 'function') {
+ callback = options;
+ options = {};
+ }
+
+ MongoClient.connect(url, options, function(err, db) {
+ if(err) return callback(err, db);
+ // Emit open and perform callback
+ self.emit("open", err, db);
+ callback(err, db);
+ });
+}
+
+/**
+ * Initialize the database connection.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the connected mongoclient or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+MongoClient.prototype.open = function(callback) {
+ // Self reference
+ var self = this;
+ // Open the db
+ this._db.open(function(err, db) {
+ if(err) return callback(err, null);
+
+ // Emit open event
+ self.emit("open", err, db);
+ // Callback
+ callback(null, self);
+ })
+}
+
+/**
+ * Close the current db connection, including all the child db instances. Emits close event if no callback is provided.
+ *
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the close method or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+MongoClient.prototype.close = function(callback) {
+ this._db.close(callback);
+}
+
+/**
+ * Create a new Db instance sharing the current socket connections.
+ *
+ * @param {String} dbName the name of the database we want to use.
+ * @return {Db} a db instance using the new database.
+ * @api public
+ */
+MongoClient.prototype.db = function(dbName) {
+ return this._db.db(dbName);
+}
+
+/**
+ * Connect to MongoDB using a url as documented at
+ *
+ * docs.mongodb.org/manual/reference/connection-string/
+ *
+ * Options
+ * - **uri_decode_auth** {Boolean, default:false} uri decode the user name and password for authentication
+ * - **db** {Object, default: null} a hash off options to set on the db object, see **Db constructor**
+ * - **server** {Object, default: null} a hash off options to set on the server objects, see **Server** constructor**
+ * - **replSet** {Object, default: null} a hash off options to set on the replSet object, see **ReplSet** constructor**
+ * - **mongos** {Object, default: null} a hash off options to set on the mongos object, see **Mongos** constructor**
+ *
+ * @param {String} url connection url for MongoDB.
+ * @param {Object} [options] optional options for insert command
+ * @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the initialized db object or null if an error occured.
+ * @return {null}
+ * @api public
+ */
+MongoClient.connect = function(url, options, callback) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ callback = typeof args[args.length - 1] == 'function' ? args.pop() : null;
+ options = args.length ? args.shift() : null;
+ options = options || {};
+
+ // Set default empty server options
+ var serverOptions = options.server || {};
+ var mongosOptions = options.mongos || {};
+ var replSetServersOptions = options.replSet || options.replSetServers || {};
+ var dbOptions = options.db || {};
+
+ // If callback is null throw an exception
+ if(callback == null) throw new Error("no callback function provided");
+
+ // Parse the string
+ var object = parse(url, options);
+ // Merge in any options for db in options object
+ if(dbOptions) {
+ for(var name in dbOptions) object.db_options[name] = dbOptions[name];
+ }
+
+ // Added the url to the options
+ object.db_options.url = url;
+
+ // Merge in any options for server in options object
+ if(serverOptions) {
+ for(var name in serverOptions) object.server_options[name] = serverOptions[name];
+ }
+
+ // Merge in any replicaset server options
+ if(replSetServersOptions) {
+ for(var name in replSetServersOptions) object.rs_options[name] = replSetServersOptions[name];
+ }
+
+ // Merge in any replicaset server options
+ if(mongosOptions) {
+ for(var name in mongosOptions) object.mongos_options[name] = mongosOptions[name];
+ }
+
+ // We need to ensure that the list of servers are only either direct members or mongos
+ // they cannot be a mix of monogs and mongod's
+ var totalNumberOfServers = object.servers.length;
+ var totalNumberOfMongosServers = 0;
+ var totalNumberOfMongodServers = 0;
+ var serverConfig = null;
+ var errorServers = {};
+
+ // Failure modes
+ if(object.servers.length == 0) throw new Error("connection string must contain at least one seed host");
+
+ // If we have no db setting for the native parser try to set the c++ one first
+ object.db_options.native_parser = _setNativeParser(object.db_options);
+ // If no auto_reconnect is set, set it to true as default for single servers
+ if(typeof object.server_options.auto_reconnect != 'boolean') {
+ object.server_options.auto_reconnect = true;
+ }
+
+ // If we have more than a server, it could be replicaset or mongos list
+ // need to verify that it's one or the other and fail if it's a mix
+ // Connect to all servers and run ismaster
+ for(var i = 0; i < object.servers.length; i++) {
+ // Set up socket options
+ var _server_options = {poolSize:1, socketOptions:{connectTimeoutMS:1000}, auto_reconnect:false};
+
+ // Ensure we have ssl setup for the servers
+ if(object.rs_options.ssl) {
+ _server_options.ssl = object.rs_options.ssl;
+ _server_options.sslValidate = object.rs_options.sslValidate;
+ _server_options.sslCA = object.rs_options.sslCA;
+ _server_options.sslCert = object.rs_options.sslCert;
+ _server_options.sslKey = object.rs_options.sslKey;
+ _server_options.sslPass = object.rs_options.sslPass;
+ } else if(object.server_options.ssl) {
+ _server_options.ssl = object.server_options.ssl;
+ _server_options.sslValidate = object.server_options.sslValidate;
+ _server_options.sslCA = object.server_options.sslCA;
+ _server_options.sslCert = object.server_options.sslCert;
+ _server_options.sslKey = object.server_options.sslKey;
+ _server_options.sslPass = object.server_options.sslPass;
+ }
+
+ // Set up the Server object
+ var _server = object.servers[i].domain_socket
+ ? new Server(object.servers[i].domain_socket, _server_options)
+ : new Server(object.servers[i].host, object.servers[i].port, _server_options);
+
+ var connectFunction = function(__server) {
+ // Attempt connect
+ new Db(object.dbName, __server, {safe:false, native_parser:false}).open(function(err, db) {
+ // Update number of servers
+ totalNumberOfServers = totalNumberOfServers - 1;
+ // If no error do the correct checks
+ if(!err) {
+ // Close the connection
+ db.close(true);
+ var isMasterDoc = db.serverConfig.isMasterDoc;
+ // Check what type of server we have
+ if(isMasterDoc.setName) totalNumberOfMongodServers++;
+ if(isMasterDoc.msg && isMasterDoc.msg == "isdbgrid") totalNumberOfMongosServers++;
+ } else {
+ errorServers[__server.host + ":" + __server.port] = __server;
+ }
+
+ if(totalNumberOfServers == 0) {
+ // If we have a mix of mongod and mongos, throw an error
+ if(totalNumberOfMongosServers > 0 && totalNumberOfMongodServers > 0)
+ return callback(new Error("cannot combine a list of replicaset seeds and mongos seeds"));
+
+ if(totalNumberOfMongodServers == 0 && object.servers.length == 1) {
+ var obj = object.servers[0];
+ serverConfig = obj.domain_socket ?
+ new Server(obj.domain_socket, object.server_options)
+ : new Server(obj.host, obj.port, object.server_options);
+ } else if(totalNumberOfMongodServers > 0 || totalNumberOfMongosServers > 0) {
+ var finalServers = object.servers
+ .filter(function(serverObj) {
+ return errorServers[serverObj.host + ":" + serverObj.port] == null;
+ })
+ .map(function(serverObj) {
+ return new Server(serverObj.host, serverObj.port, object.server_options);
+ });
+ // Clean out any error servers
+ errorServers = {};
+ // Set up the final configuration
+ if(totalNumberOfMongodServers > 0) {
+ serverConfig = new ReplSet(finalServers, object.rs_options);
+ } else {
+ serverConfig = new Mongos(finalServers, object.mongos_options);
+ }
+ }
+
+ if(serverConfig == null) return callback(new Error("Could not locate any valid servers in initial seed list"));
+ // Ensure no firing off open event before we are ready
+ serverConfig.emitOpen = false;
+ // Set up all options etc and connect to the database
+ _finishConnecting(serverConfig, object, options, callback)
+ }
+ });
+ }
+
+ // Wrap the context of the call
+ connectFunction(_server);
+ }
+}
+
+var _setNativeParser = function(db_options) {
+ if(typeof db_options.native_parser == 'boolean') return db_options.native_parser;
+
+ try {
+ require('bson').BSONNative.BSON;
+ return true;
+ } catch(err) {
+ return false;
+ }
+}
+
+var _finishConnecting = function(serverConfig, object, options, callback) {
+ // Safe settings
+ var safe = {};
+ // Build the safe parameter if needed
+ if(object.db_options.journal) safe.j = object.db_options.journal;
+ if(object.db_options.w) safe.w = object.db_options.w;
+ if(object.db_options.fsync) safe.fsync = object.db_options.fsync;
+ if(object.db_options.wtimeoutMS) safe.wtimeout = object.db_options.wtimeoutMS;
+
+ // If we have a read Preference set
+ if(object.db_options.read_preference) {
+ var readPreference = new ReadPreference(object.db_options.read_preference);
+ // If we have the tags set up
+ if(object.db_options.read_preference_tags)
+ readPreference = new ReadPreference(object.db_options.read_preference, object.db_options.read_preference_tags);
+ // Add the read preference
+ object.db_options.readPreference = readPreference;
+ }
+
+ // No safe mode if no keys
+ if(Object.keys(safe).length == 0) safe = false;
+
+ // Add the safe object
+ object.db_options.safe = safe;
+
+ // Set up the db options
+ var db = new Db(object.dbName, serverConfig, object.db_options);
+ // Open the db
+ db.open(function(err, db){
+ if(err) return callback(err, null);
+
+ if(db.options !== null && !db.options.safe && !db.options.journal
+ && !db.options.w && !db.options.fsync && typeof db.options.w != 'number'
+ && (db.options.safe == false && object.db_options.url.indexOf("safe=") == -1)) {
+ db.options.w = 1;
+ }
+
+ if(err == null && object.auth){
+ // What db to authenticate against
+ var authentication_db = db;
+ if(object.db_options && object.db_options.authSource) {
+ authentication_db = db.db(object.db_options.authSource);
+ }
+
+ // Build options object
+ var options = {};
+ if(object.db_options.authMechanism) options.authMechanism = object.db_options.authMechanism;
+
+ // Authenticate
+ authentication_db.authenticate(object.auth.user, object.auth.password, options, function(err, success){
+ if(success){
+ callback(null, db);
+ } else {
+ if(db) db.close();
+ callback(err ? err : new Error('Could not authenticate user ' + auth[0]), null);
+ }
+ });
+ } else {
+ callback(err, db);
+ }
+ });
+}
+
+
+exports.MongoClient = MongoClient;
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js b/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js
new file mode 100644
index 0000000..b27b812
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js
@@ -0,0 +1,144 @@
+var Long = require('bson').Long
+ , timers = require('timers');
+
+// Set processor, setImmediate if 0.10 otherwise nextTick
+var processor = timers.setImmediate ? timers.setImmediate : process.nextTick;
+
+/**
+ Reply message from mongo db
+**/
+var MongoReply = exports.MongoReply = function() {
+ this.documents = [];
+ this.index = 0;
+};
+
+MongoReply.prototype.parseHeader = function(binary_reply, bson) {
+ // Unpack the standard header first
+ this.messageLength = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
+ this.index = this.index + 4;
+ // Fetch the request id for this reply
+ this.requestId = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
+ this.index = this.index + 4;
+ // Fetch the id of the request that triggered the response
+ this.responseTo = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
+ // Skip op-code field
+ this.index = this.index + 4 + 4;
+ // Unpack the reply message
+ this.responseFlag = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
+ this.index = this.index + 4;
+ // Unpack the cursor id (a 64 bit long integer)
+ var low_bits = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
+ this.index = this.index + 4;
+ var high_bits = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
+ this.index = this.index + 4;
+ this.cursorId = new Long(low_bits, high_bits);
+ // Unpack the starting from
+ this.startingFrom = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
+ this.index = this.index + 4;
+ // Unpack the number of objects returned
+ this.numberReturned = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
+ this.index = this.index + 4;
+}
+
+MongoReply.prototype.parseBody = function(binary_reply, bson, raw, callback) {
+ raw = raw == null ? false : raw;
+ // Just set a doc limit for deserializing
+ var docLimitSize = 1024*20;
+
+ // If our message length is very long, let's switch to process.nextTick for messages
+ if(this.messageLength > docLimitSize) {
+ var batchSize = this.numberReturned;
+ this.documents = new Array(this.numberReturned);
+
+ // Just walk down until we get a positive number >= 1
+ for(var i = 50; i > 0; i--) {
+ if((this.numberReturned/i) >= 1) {
+ batchSize = i;
+ break;
+ }
+ }
+
+ // Actual main creator of the processFunction setting internal state to control the flow
+ var parseFunction = function(_self, _binary_reply, _batchSize, _numberReturned) {
+ var object_index = 0;
+ // Internal loop process that will use nextTick to ensure we yield some time
+ var processFunction = function() {
+ // Adjust batchSize if we have less results left than batchsize
+ if((_numberReturned - object_index) < _batchSize) {
+ _batchSize = _numberReturned - object_index;
+ }
+
+ // If raw just process the entries
+ if(raw) {
+ // Iterate over the batch
+ for(var i = 0; i < _batchSize; i++) {
+ // Are we done ?
+ if(object_index <= _numberReturned) {
+ // Read the size of the bson object
+ var bsonObjectSize = _binary_reply[_self.index] | _binary_reply[_self.index + 1] << 8 | _binary_reply[_self.index + 2] << 16 | _binary_reply[_self.index + 3] << 24;
+ // If we are storing the raw responses to pipe straight through
+ _self.documents[object_index] = binary_reply.slice(_self.index, _self.index + bsonObjectSize);
+ // Adjust binary index to point to next block of binary bson data
+ _self.index = _self.index + bsonObjectSize;
+ // Update number of docs parsed
+ object_index = object_index + 1;
+ }
+ }
+ } else {
+ try {
+ // Parse documents
+ _self.index = bson.deserializeStream(binary_reply, _self.index, _batchSize, _self.documents, object_index);
+ // Adjust index
+ object_index = object_index + _batchSize;
+ } catch (err) {
+ return callback(err);
+ }
+ }
+
+ // If we have more documents process NextTick
+ if(object_index < _numberReturned) {
+ processor(processFunction);
+ } else {
+ callback(null);
+ }
+ }
+
+ // Return the process function
+ return processFunction;
+ }(this, binary_reply, batchSize, this.numberReturned)();
+ } else {
+ try {
+ // Let's unpack all the bson documents, deserialize them and store them
+ for(var object_index = 0; object_index < this.numberReturned; object_index++) {
+ // Read the size of the bson object
+ var bsonObjectSize = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
+ // If we are storing the raw responses to pipe straight through
+ if(raw) {
+ // Deserialize the object and add to the documents array
+ this.documents.push(binary_reply.slice(this.index, this.index + bsonObjectSize));
+ } else {
+ // Deserialize the object and add to the documents array
+ this.documents.push(bson.deserialize(binary_reply.slice(this.index, this.index + bsonObjectSize)));
+ }
+ // Adjust binary index to point to next block of binary bson data
+ this.index = this.index + bsonObjectSize;
+ }
+ } catch(err) {
+ return callback(err);
+ }
+
+ // No error return
+ callback(null);
+ }
+}
+
+MongoReply.prototype.is_error = function(){
+ if(this.documents.length == 1) {
+ return this.documents[0].ok == 1 ? false : true;
+ }
+ return false;
+};
+
+MongoReply.prototype.error_message = function() {
+ return this.documents.length == 1 && this.documents[0].ok == 1 ? '' : this.documents[0].errmsg;
+};
\ No newline at end of file
diff --git a/node_modules/mongodb/lib/mongodb/utils.js b/node_modules/mongodb/lib/mongodb/utils.js
new file mode 100644
index 0000000..087789d
--- /dev/null
+++ b/node_modules/mongodb/lib/mongodb/utils.js
@@ -0,0 +1,137 @@
+/**
+ * Sort functions, Normalize and prepare sort parameters
+ */
+var formatSortValue = exports.formatSortValue = function(sortDirection) {
+ var value = ("" + sortDirection).toLowerCase();
+
+ switch (value) {
+ case 'ascending':
+ case 'asc':
+ case '1':
+ return 1;
+ case 'descending':
+ case 'desc':
+ case '-1':
+ return -1;
+ default:
+ throw new Error("Illegal sort clause, must be of the form "
+ + "[['field1', '(ascending|descending)'], "
+ + "['field2', '(ascending|descending)']]");
+ }
+};
+
+var formattedOrderClause = exports.formattedOrderClause = function(sortValue) {
+ var orderBy = {};
+
+ if (Array.isArray(sortValue)) {
+ for(var i = 0; i < sortValue.length; i++) {
+ if(sortValue[i].constructor == String) {
+ orderBy[sortValue[i]] = 1;
+ } else {
+ orderBy[sortValue[i][0]] = formatSortValue(sortValue[i][1]);
+ }
+ }
+ } else if(Object.prototype.toString.call(sortValue) === '[object Object]') {
+ orderBy = sortValue;
+ } else if (sortValue.constructor == String) {
+ orderBy[sortValue] = 1;
+ } else {
+ throw new Error("Illegal sort clause, must be of the form " +
+ "[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]");
+ }
+
+ return orderBy;
+};
+
+exports.encodeInt = function(value) {
+ var buffer = new Buffer(4);
+ buffer[3] = (value >> 24) & 0xff;
+ buffer[2] = (value >> 16) & 0xff;
+ buffer[1] = (value >> 8) & 0xff;
+ buffer[0] = value & 0xff;
+ return buffer;
+}
+
+exports.encodeIntInPlace = function(value, buffer, index) {
+ buffer[index + 3] = (value >> 24) & 0xff;
+ buffer[index + 2] = (value >> 16) & 0xff;
+ buffer[index + 1] = (value >> 8) & 0xff;
+ buffer[index] = value & 0xff;
+}
+
+exports.encodeCString = function(string) {
+ var buf = new Buffer(string, 'utf8');
+ return [buf, new Buffer([0])];
+}
+
+exports.decodeUInt32 = function(array, index) {
+ return array[index] | array[index + 1] << 8 | array[index + 2] << 16 | array[index + 3] << 24;
+}
+
+// Decode the int
+exports.decodeUInt8 = function(array, index) {
+ return array[index];
+}
+
+/**
+ * Context insensitive type checks
+ */
+
+var toString = Object.prototype.toString;
+
+exports.isObject = function (arg) {
+ return '[object Object]' == toString.call(arg)
+}
+
+exports.isArray = function (arg) {
+ return Array.isArray(arg) ||
+ 'object' == typeof arg && '[object Array]' == toString.call(arg)
+}
+
+exports.isDate = function (arg) {
+ return 'object' == typeof arg && '[object Date]' == toString.call(arg)
+}
+
+exports.isRegExp = function (arg) {
+ return 'object' == typeof arg && '[object RegExp]' == toString.call(arg)
+}
+
+/**
+ * Wrap a Mongo error document in an Error instance
+ * @ignore
+ * @api private
+ */
+exports.toError = function(error) {
+ if (error instanceof Error) return error;
+
+ var msg = error.err || error.errmsg || error;
+ var e = new Error(msg);
+ e.name = 'MongoError';
+
+ // Get all object keys
+ var keys = typeof error == 'object'
+ ? Object.keys(error)
+ : [];
+
+ for(var i = 0; i < keys.length; i++) {
+ e[keys[i]] = error[keys[i]];
+ }
+
+ return e;
+}
+
+/**
+ * Convert a single level object to an array
+ * @ignore
+ * @api private
+ */
+exports.objectToArray = function(object) {
+ var list = [];
+
+ for(var name in object) {
+ list.push(object[name])
+ }
+
+ return list;
+}
+
diff --git a/node_modules/mongodb/node_modules/bson/.travis.yml b/node_modules/mongodb/node_modules/bson/.travis.yml
new file mode 100644
index 0000000..94740d0
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+ - 0.6
+ - 0.8
+ - 0.9 # development version of 0.8, may be unstable
\ No newline at end of file
diff --git a/node_modules/mongodb/node_modules/bson/Makefile b/node_modules/mongodb/node_modules/bson/Makefile
new file mode 100644
index 0000000..77ce4e0
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/Makefile
@@ -0,0 +1,19 @@
+NODE = node
+NPM = npm
+NODEUNIT = node_modules/nodeunit/bin/nodeunit
+
+all: clean node_gyp
+
+test: clean node_gyp
+ npm test
+
+node_gyp: clean
+ node-gyp configure build
+
+clean:
+ node-gyp clean
+
+browserify:
+ node_modules/.bin/onejs build browser_build/package.json browser_build/bson.js
+
+.PHONY: all
diff --git a/node_modules/mongodb/node_modules/bson/README.md b/node_modules/mongodb/node_modules/bson/README.md
new file mode 100644
index 0000000..1a6fc2b
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/README.md
@@ -0,0 +1,45 @@
+Javascript + C++ BSON parser
+============================
+
+This BSON parser is primarily meant for usage with the `mongodb` node.js driver. However thanks to such wonderful tools at `onejs` we are able to package up a BSON parser that will work in the browser aswell. The current build is located in the `browser_build/bson.js` file.
+
+A simple example on how to use it
+
+
+
+
+
+
+
+
+ It's got two simple methods to use in your application.
+
+ * BSON.serialize(object, checkKeys, asBuffer, serializeFunctions)
+ * @param {Object} object the Javascript object to serialize.
+ * @param {Boolean} checkKeys the serializer will check if keys are valid.
+ * @param {Boolean} asBuffer return the serialized object as a Buffer object **(ignore)**.
+ * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**
+ * @return {TypedArray/Array} returns a TypedArray or Array depending on what your browser supports
+
+ * BSON.deserialize(buffer, options, isArray)
+ * Options
+ * **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized.
+ * **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse.
+ * **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function.
+ * @param {TypedArray/Array} a TypedArray/Array containing the BSON data
+ * @param {Object} [options] additional options used for the deserialization.
+ * @param {Boolean} [isArray] ignore used for recursive parsing.
+ * @return {Object} returns the deserialized Javascript Object.
diff --git a/node_modules/mongodb/node_modules/bson/binding.gyp b/node_modules/mongodb/node_modules/bson/binding.gyp
new file mode 100644
index 0000000..42445d3
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/binding.gyp
@@ -0,0 +1,17 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'bson',
+ 'sources': [ 'ext/bson.cc' ],
+ 'cflags!': [ '-fno-exceptions' ],
+ 'cflags_cc!': [ '-fno-exceptions' ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES'
+ }
+ }]
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/node_modules/mongodb/node_modules/bson/browser_build/bson.js b/node_modules/mongodb/node_modules/bson/browser_build/bson.js
new file mode 100644
index 0000000..7132496
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/browser_build/bson.js
@@ -0,0 +1,4815 @@
+var bson = (function(){
+
+ var pkgmap = {},
+ global = {},
+ nativeRequire = typeof require != 'undefined' && require,
+ lib, ties, main, async;
+
+ function exports(){ return main(); };
+
+ exports.main = exports;
+ exports.module = module;
+ exports.packages = pkgmap;
+ exports.pkg = pkg;
+ exports.require = function require(uri){ return pkgmap.main.index.require(uri); };
+
+
+ ties = {};
+
+ aliases = {};
+
+
+ return exports;
+
+function join() {
+ return normalize(Array.prototype.join.call(arguments, "/"));
+};
+
+function normalize(path) {
+ var ret = [], parts = path.split('/'), cur, prev;
+
+ var i = 0, l = parts.length-1;
+ for (; i <= l; i++) {
+ cur = parts[i];
+
+ if (cur === "." && prev !== undefined) continue;
+
+ if (cur === ".." && ret.length && prev !== ".." && prev !== "." && prev !== undefined) {
+ ret.pop();
+ prev = ret.slice(-1)[0];
+ } else {
+ if (prev === ".") ret.pop();
+ ret.push(cur);
+ prev = cur;
+ }
+ }
+
+ return ret.join("/");
+};
+
+function dirname(path) {
+ return path && path.substr(0, path.lastIndexOf("/")) || ".";
+};
+
+function findModule(workingModule, uri){
+ var moduleId = join(dirname(workingModule.id), uri).replace(/\.js$/, ''),
+ moduleIndexId = join(moduleId, 'index'),
+ pkg = workingModule.pkg,
+ module;
+
+ var i = pkg.modules.length,
+ id;
+
+ while(i-->0){
+ id = pkg.modules[i].id;
+ if(id==moduleId || id == moduleIndexId){
+ module = pkg.modules[i];
+ break;
+ }
+ }
+
+ return module;
+}
+
+function newRequire(callingModule){
+ function require(uri){
+ var module, pkg;
+
+ if(/^\./.test(uri)){
+ module = findModule(callingModule, uri);
+ } else if ( ties && ties.hasOwnProperty( uri ) ) {
+ return ties[uri];
+ } else if ( aliases && aliases.hasOwnProperty( uri ) ) {
+ return require(aliases[uri]);
+ } else {
+ pkg = pkgmap[uri];
+
+ if(!pkg && nativeRequire){
+ try {
+ pkg = nativeRequire(uri);
+ } catch (nativeRequireError) {}
+
+ if(pkg) return pkg;
+ }
+
+ if(!pkg){
+ throw new Error('Cannot find module "'+uri+'" @[module: '+callingModule.id+' package: '+callingModule.pkg.name+']');
+ }
+
+ module = pkg.index;
+ }
+
+ if(!module){
+ throw new Error('Cannot find module "'+uri+'" @[module: '+callingModule.id+' package: '+callingModule.pkg.name+']');
+ }
+
+ module.parent = callingModule;
+ return module.call();
+ };
+
+
+ return require;
+}
+
+
+function module(parent, id, wrapper){
+ var mod = { pkg: parent, id: id, wrapper: wrapper },
+ cached = false;
+
+ mod.exports = {};
+ mod.require = newRequire(mod);
+
+ mod.call = function(){
+ if(cached) {
+ return mod.exports;
+ }
+
+ cached = true;
+
+ global.require = mod.require;
+
+ mod.wrapper(mod, mod.exports, global, global.require);
+ return mod.exports;
+ };
+
+ if(parent.mainModuleId == mod.id){
+ parent.index = mod;
+ parent.parents.length === 0 && ( main = mod.call );
+ }
+
+ parent.modules.push(mod);
+}
+
+function pkg(/* [ parentId ...], wrapper */){
+ var wrapper = arguments[ arguments.length - 1 ],
+ parents = Array.prototype.slice.call(arguments, 0, arguments.length - 1),
+ ctx = wrapper(parents);
+
+
+ pkgmap[ctx.name] = ctx;
+
+ arguments.length == 1 && ( pkgmap.main = ctx );
+
+ return function(modules){
+ var id;
+ for(id in modules){
+ module(ctx, id, modules[id]);
+ }
+ };
+}
+
+
+}(this));
+
+bson.pkg(function(parents){
+
+ return {
+ 'name' : 'bson',
+ 'mainModuleId' : 'bson',
+ 'modules' : [],
+ 'parents' : parents
+ };
+
+})({ 'binary': function(module, exports, global, require, undefined){
+ /**
+ * Module dependencies.
+ */
+if(typeof window === 'undefined') {
+ var Buffer = require('buffer').Buffer; // TODO just use global Buffer
+}
+
+// Binary default subtype
+var BSON_BINARY_SUBTYPE_DEFAULT = 0;
+
+/**
+ * @ignore
+ * @api private
+ */
+var writeStringToArray = function(data) {
+ // Create a buffer
+ var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(data.length)) : new Array(data.length);
+ // Write the content to the buffer
+ for(var i = 0; i < data.length; i++) {
+ buffer[i] = data.charCodeAt(i);
+ }
+ // Write the string to the buffer
+ return buffer;
+}
+
+/**
+ * Convert Array ot Uint8Array to Binary String
+ *
+ * @ignore
+ * @api private
+ */
+var convertArraytoUtf8BinaryString = function(byteArray, startIndex, endIndex) {
+ var result = "";
+ for(var i = startIndex; i < endIndex; i++) {
+ result = result + String.fromCharCode(byteArray[i]);
+ }
+ return result;
+};
+
+/**
+ * A class representation of the BSON Binary type.
+ *
+ * Sub types
+ * - **BSON.BSON_BINARY_SUBTYPE_DEFAULT**, default BSON type.
+ * - **BSON.BSON_BINARY_SUBTYPE_FUNCTION**, BSON function type.
+ * - **BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY**, BSON byte array type.
+ * - **BSON.BSON_BINARY_SUBTYPE_UUID**, BSON uuid type.
+ * - **BSON.BSON_BINARY_SUBTYPE_MD5**, BSON md5 type.
+ * - **BSON.BSON_BINARY_SUBTYPE_USER_DEFINED**, BSON user defined type.
+ *
+ * @class Represents the Binary BSON type.
+ * @param {Buffer} buffer a buffer object containing the binary data.
+ * @param {Number} [subType] the option binary type.
+ * @return {Grid}
+ */
+function Binary(buffer, subType) {
+ if(!(this instanceof Binary)) return new Binary(buffer, subType);
+
+ this._bsontype = 'Binary';
+
+ if(buffer instanceof Number) {
+ this.sub_type = buffer;
+ this.position = 0;
+ } else {
+ this.sub_type = subType == null ? BSON_BINARY_SUBTYPE_DEFAULT : subType;
+ this.position = 0;
+ }
+
+ if(buffer != null && !(buffer instanceof Number)) {
+ // Only accept Buffer, Uint8Array or Arrays
+ if(typeof buffer == 'string') {
+ // Different ways of writing the length of the string for the different types
+ if(typeof Buffer != 'undefined') {
+ this.buffer = new Buffer(buffer);
+ } else if(typeof Uint8Array != 'undefined' || (Object.prototype.toString.call(buffer) == '[object Array]')) {
+ this.buffer = writeStringToArray(buffer);
+ } else {
+ throw new Error("only String, Buffer, Uint8Array or Array accepted");
+ }
+ } else {
+ this.buffer = buffer;
+ }
+ this.position = buffer.length;
+ } else {
+ if(typeof Buffer != 'undefined') {
+ this.buffer = new Buffer(Binary.BUFFER_SIZE);
+ } else if(typeof Uint8Array != 'undefined'){
+ this.buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE));
+ } else {
+ this.buffer = new Array(Binary.BUFFER_SIZE);
+ }
+ // Set position to start of buffer
+ this.position = 0;
+ }
+};
+
+/**
+ * Updates this binary with byte_value.
+ *
+ * @param {Character} byte_value a single byte we wish to write.
+ * @api public
+ */
+Binary.prototype.put = function put(byte_value) {
+ // If it's a string and a has more than one character throw an error
+ if(byte_value['length'] != null && typeof byte_value != 'number' && byte_value.length != 1) throw new Error("only accepts single character String, Uint8Array or Array");
+ if(typeof byte_value != 'number' && byte_value < 0 || byte_value > 255) throw new Error("only accepts number in a valid unsigned byte range 0-255");
+
+ // Decode the byte value once
+ var decoded_byte = null;
+ if(typeof byte_value == 'string') {
+ decoded_byte = byte_value.charCodeAt(0);
+ } else if(byte_value['length'] != null) {
+ decoded_byte = byte_value[0];
+ } else {
+ decoded_byte = byte_value;
+ }
+
+ if(this.buffer.length > this.position) {
+ this.buffer[this.position++] = decoded_byte;
+ } else {
+ if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) {
+ // Create additional overflow buffer
+ var buffer = new Buffer(Binary.BUFFER_SIZE + this.buffer.length);
+ // Combine the two buffers together
+ this.buffer.copy(buffer, 0, 0, this.buffer.length);
+ this.buffer = buffer;
+ this.buffer[this.position++] = decoded_byte;
+ } else {
+ var buffer = null;
+ // Create a new buffer (typed or normal array)
+ if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') {
+ buffer = new Uint8Array(new ArrayBuffer(Binary.BUFFER_SIZE + this.buffer.length));
+ } else {
+ buffer = new Array(Binary.BUFFER_SIZE + this.buffer.length);
+ }
+
+ // We need to copy all the content to the new array
+ for(var i = 0; i < this.buffer.length; i++) {
+ buffer[i] = this.buffer[i];
+ }
+
+ // Reassign the buffer
+ this.buffer = buffer;
+ // Write the byte
+ this.buffer[this.position++] = decoded_byte;
+ }
+ }
+};
+
+/**
+ * Writes a buffer or string to the binary.
+ *
+ * @param {Buffer|String} string a string or buffer to be written to the Binary BSON object.
+ * @param {Number} offset specify the binary of where to write the content.
+ * @api public
+ */
+Binary.prototype.write = function write(string, offset) {
+ offset = typeof offset == 'number' ? offset : this.position;
+
+ // If the buffer is to small let's extend the buffer
+ if(this.buffer.length < offset + string.length) {
+ var buffer = null;
+ // If we are in node.js
+ if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) {
+ buffer = new Buffer(this.buffer.length + string.length);
+ this.buffer.copy(buffer, 0, 0, this.buffer.length);
+ } else if(Object.prototype.toString.call(this.buffer) == '[object Uint8Array]') {
+ // Create a new buffer
+ buffer = new Uint8Array(new ArrayBuffer(this.buffer.length + string.length))
+ // Copy the content
+ for(var i = 0; i < this.position; i++) {
+ buffer[i] = this.buffer[i];
+ }
+ }
+
+ // Assign the new buffer
+ this.buffer = buffer;
+ }
+
+ if(typeof Buffer != 'undefined' && Buffer.isBuffer(string) && Buffer.isBuffer(this.buffer)) {
+ string.copy(this.buffer, offset, 0, string.length);
+ this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position;
+ // offset = string.length
+ } else if(typeof Buffer != 'undefined' && typeof string == 'string' && Buffer.isBuffer(this.buffer)) {
+ this.buffer.write(string, 'binary', offset);
+ this.position = (offset + string.length) > this.position ? (offset + string.length) : this.position;
+ // offset = string.length;
+ } else if(Object.prototype.toString.call(string) == '[object Uint8Array]'
+ || Object.prototype.toString.call(string) == '[object Array]' && typeof string != 'string') {
+ for(var i = 0; i < string.length; i++) {
+ this.buffer[offset++] = string[i];
+ }
+
+ this.position = offset > this.position ? offset : this.position;
+ } else if(typeof string == 'string') {
+ for(var i = 0; i < string.length; i++) {
+ this.buffer[offset++] = string.charCodeAt(i);
+ }
+
+ this.position = offset > this.position ? offset : this.position;
+ }
+};
+
+/**
+ * Reads **length** bytes starting at **position**.
+ *
+ * @param {Number} position read from the given position in the Binary.
+ * @param {Number} length the number of bytes to read.
+ * @return {Buffer}
+ * @api public
+ */
+Binary.prototype.read = function read(position, length) {
+ length = length && length > 0
+ ? length
+ : this.position;
+
+ // Let's return the data based on the type we have
+ if(this.buffer['slice']) {
+ return this.buffer.slice(position, position + length);
+ } else {
+ // Create a buffer to keep the result
+ var buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(length)) : new Array(length);
+ for(var i = 0; i < length; i++) {
+ buffer[i] = this.buffer[position++];
+ }
+ }
+ // Return the buffer
+ return buffer;
+};
+
+/**
+ * Returns the value of this binary as a string.
+ *
+ * @return {String}
+ * @api public
+ */
+Binary.prototype.value = function value(asRaw) {
+ asRaw = asRaw == null ? false : asRaw;
+
+ // If it's a node.js buffer object
+ if(typeof Buffer != 'undefined' && Buffer.isBuffer(this.buffer)) {
+ return asRaw ? this.buffer.slice(0, this.position) : this.buffer.toString('binary', 0, this.position);
+ } else {
+ if(asRaw) {
+ // we support the slice command use it
+ if(this.buffer['slice'] != null) {
+ return this.buffer.slice(0, this.position);
+ } else {
+ // Create a new buffer to copy content to
+ var newBuffer = Object.prototype.toString.call(this.buffer) == '[object Uint8Array]' ? new Uint8Array(new ArrayBuffer(this.position)) : new Array(this.position);
+ // Copy content
+ for(var i = 0; i < this.position; i++) {
+ newBuffer[i] = this.buffer[i];
+ }
+ // Return the buffer
+ return newBuffer;
+ }
+ } else {
+ return convertArraytoUtf8BinaryString(this.buffer, 0, this.position);
+ }
+ }
+};
+
+/**
+ * Length.
+ *
+ * @return {Number} the length of the binary.
+ * @api public
+ */
+Binary.prototype.length = function length() {
+ return this.position;
+};
+
+/**
+ * @ignore
+ * @api private
+ */
+Binary.prototype.toJSON = function() {
+ return this.buffer != null ? this.buffer.toString('base64') : '';
+}
+
+/**
+ * @ignore
+ * @api private
+ */
+Binary.prototype.toString = function(format) {
+ return this.buffer != null ? this.buffer.slice(0, this.position).toString(format) : '';
+}
+
+Binary.BUFFER_SIZE = 256;
+
+/**
+ * Default BSON type
+ *
+ * @classconstant SUBTYPE_DEFAULT
+ **/
+Binary.SUBTYPE_DEFAULT = 0;
+/**
+ * Function BSON type
+ *
+ * @classconstant SUBTYPE_DEFAULT
+ **/
+Binary.SUBTYPE_FUNCTION = 1;
+/**
+ * Byte Array BSON type
+ *
+ * @classconstant SUBTYPE_DEFAULT
+ **/
+Binary.SUBTYPE_BYTE_ARRAY = 2;
+/**
+ * OLD UUID BSON type
+ *
+ * @classconstant SUBTYPE_DEFAULT
+ **/
+Binary.SUBTYPE_UUID_OLD = 3;
+/**
+ * UUID BSON type
+ *
+ * @classconstant SUBTYPE_DEFAULT
+ **/
+Binary.SUBTYPE_UUID = 4;
+/**
+ * MD5 BSON type
+ *
+ * @classconstant SUBTYPE_DEFAULT
+ **/
+Binary.SUBTYPE_MD5 = 5;
+/**
+ * User BSON type
+ *
+ * @classconstant SUBTYPE_DEFAULT
+ **/
+Binary.SUBTYPE_USER_DEFINED = 128;
+
+/**
+ * Expose.
+ */
+exports.Binary = Binary;
+
+
+},
+
+
+
+'binary_parser': function(module, exports, global, require, undefined){
+ /**
+ * Binary Parser.
+ * Jonas Raoni Soares Silva
+ * http://jsfromhell.com/classes/binary-parser [v1.0]
+ */
+var chr = String.fromCharCode;
+
+var maxBits = [];
+for (var i = 0; i < 64; i++) {
+ maxBits[i] = Math.pow(2, i);
+}
+
+function BinaryParser (bigEndian, allowExceptions) {
+ if(!(this instanceof BinaryParser)) return new BinaryParser(bigEndian, allowExceptions);
+
+ this.bigEndian = bigEndian;
+ this.allowExceptions = allowExceptions;
+};
+
+BinaryParser.warn = function warn (msg) {
+ if (this.allowExceptions) {
+ throw new Error(msg);
+ }
+
+ return 1;
+};
+
+BinaryParser.decodeFloat = function decodeFloat (data, precisionBits, exponentBits) {
+ var b = new this.Buffer(this.bigEndian, data);
+
+ b.checkBuffer(precisionBits + exponentBits + 1);
+
+ var bias = maxBits[exponentBits - 1] - 1
+ , signal = b.readBits(precisionBits + exponentBits, 1)
+ , exponent = b.readBits(precisionBits, exponentBits)
+ , significand = 0
+ , divisor = 2
+ , curByte = b.buffer.length + (-precisionBits >> 3) - 1;
+
+ do {
+ for (var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 );
+ } while (precisionBits -= startBit);
+
+ return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 );
+};
+
+BinaryParser.decodeInt = function decodeInt (data, bits, signed, forceBigEndian) {
+ var b = new this.Buffer(this.bigEndian || forceBigEndian, data)
+ , x = b.readBits(0, bits)
+ , max = maxBits[bits]; //max = Math.pow( 2, bits );
+
+ return signed && x >= max / 2
+ ? x - max
+ : x;
+};
+
+BinaryParser.encodeFloat = function encodeFloat (data, precisionBits, exponentBits) {
+ var bias = maxBits[exponentBits - 1] - 1
+ , minExp = -bias + 1
+ , maxExp = bias
+ , minUnnormExp = minExp - precisionBits
+ , n = parseFloat(data)
+ , status = isNaN(n) || n == -Infinity || n == +Infinity ? n : 0
+ , exp = 0
+ , len = 2 * bias + 1 + precisionBits + 3
+ , bin = new Array(len)
+ , signal = (n = status !== 0 ? 0 : n) < 0
+ , intPart = Math.floor(n = Math.abs(n))
+ , floatPart = n - intPart
+ , lastBit
+ , rounded
+ , result
+ , i
+ , j;
+
+ for (i = len; i; bin[--i] = 0);
+
+ for (i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor(intPart / 2));
+
+ for (i = bias + 1; floatPart > 0 && i; (bin[++i] = ((floatPart *= 2) >= 1) - 0 ) && --floatPart);
+
+ for (i = -1; ++i < len && !bin[i];);
+
+ if (bin[(lastBit = precisionBits - 1 + (i = (exp = bias + 1 - i) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - (exp = minExp - 1))) + 1]) {
+ if (!(rounded = bin[lastBit])) {
+ for (j = lastBit + 2; !rounded && j < len; rounded = bin[j++]);
+ }
+
+ for (j = lastBit + 1; rounded && --j >= 0; (bin[j] = !bin[j] - 0) && (rounded = 0));
+ }
+
+ for (i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i];);
+
+ if ((exp = bias + 1 - i) >= minExp && exp <= maxExp) {
+ ++i;
+ } else if (exp < minExp) {
+ exp != bias + 1 - len && exp < minUnnormExp && this.warn("encodeFloat::float underflow");
+ i = bias + 1 - (exp = minExp - 1);
+ }
+
+ if (intPart || status !== 0) {
+ this.warn(intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status);
+ exp = maxExp + 1;
+ i = bias + 2;
+
+ if (status == -Infinity) {
+ signal = 1;
+ } else if (isNaN(status)) {
+ bin[i] = 1;
+ }
+ }
+
+ for (n = Math.abs(exp + bias), j = exponentBits + 1, result = ""; --j; result = (n % 2) + result, n = n >>= 1);
+
+ for (n = 0, j = 0, i = (result = (signal ? "1" : "0") + result + bin.slice(i, i + precisionBits).join("")).length, r = []; i; j = (j + 1) % 8) {
+ n += (1 << j) * result.charAt(--i);
+ if (j == 7) {
+ r[r.length] = String.fromCharCode(n);
+ n = 0;
+ }
+ }
+
+ r[r.length] = n
+ ? String.fromCharCode(n)
+ : "";
+
+ return (this.bigEndian ? r.reverse() : r).join("");
+};
+
+BinaryParser.encodeInt = function encodeInt (data, bits, signed, forceBigEndian) {
+ var max = maxBits[bits];
+
+ if (data >= max || data < -(max / 2)) {
+ this.warn("encodeInt::overflow");
+ data = 0;
+ }
+
+ if (data < 0) {
+ data += max;
+ }
+
+ for (var r = []; data; r[r.length] = String.fromCharCode(data % 256), data = Math.floor(data / 256));
+
+ for (bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0");
+
+ return ((this.bigEndian || forceBigEndian) ? r.reverse() : r).join("");
+};
+
+BinaryParser.toSmall = function( data ){ return this.decodeInt( data, 8, true ); };
+BinaryParser.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); };
+BinaryParser.toByte = function( data ){ return this.decodeInt( data, 8, false ); };
+BinaryParser.fromByte = function( data ){ return this.encodeInt( data, 8, false ); };
+BinaryParser.toShort = function( data ){ return this.decodeInt( data, 16, true ); };
+BinaryParser.fromShort = function( data ){ return this.encodeInt( data, 16, true ); };
+BinaryParser.toWord = function( data ){ return this.decodeInt( data, 16, false ); };
+BinaryParser.fromWord = function( data ){ return this.encodeInt( data, 16, false ); };
+BinaryParser.toInt = function( data ){ return this.decodeInt( data, 32, true ); };
+BinaryParser.fromInt = function( data ){ return this.encodeInt( data, 32, true ); };
+BinaryParser.toLong = function( data ){ return this.decodeInt( data, 64, true ); };
+BinaryParser.fromLong = function( data ){ return this.encodeInt( data, 64, true ); };
+BinaryParser.toDWord = function( data ){ return this.decodeInt( data, 32, false ); };
+BinaryParser.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); };
+BinaryParser.toQWord = function( data ){ return this.decodeInt( data, 64, true ); };
+BinaryParser.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); };
+BinaryParser.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); };
+BinaryParser.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); };
+BinaryParser.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); };
+BinaryParser.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); };
+
+// Factor out the encode so it can be shared by add_header and push_int32
+BinaryParser.encode_int32 = function encode_int32 (number, asArray) {
+ var a, b, c, d, unsigned;
+ unsigned = (number < 0) ? (number + 0x100000000) : number;
+ a = Math.floor(unsigned / 0xffffff);
+ unsigned &= 0xffffff;
+ b = Math.floor(unsigned / 0xffff);
+ unsigned &= 0xffff;
+ c = Math.floor(unsigned / 0xff);
+ unsigned &= 0xff;
+ d = Math.floor(unsigned);
+ return asArray ? [chr(a), chr(b), chr(c), chr(d)] : chr(a) + chr(b) + chr(c) + chr(d);
+};
+
+BinaryParser.encode_int64 = function encode_int64 (number) {
+ var a, b, c, d, e, f, g, h, unsigned;
+ unsigned = (number < 0) ? (number + 0x10000000000000000) : number;
+ a = Math.floor(unsigned / 0xffffffffffffff);
+ unsigned &= 0xffffffffffffff;
+ b = Math.floor(unsigned / 0xffffffffffff);
+ unsigned &= 0xffffffffffff;
+ c = Math.floor(unsigned / 0xffffffffff);
+ unsigned &= 0xffffffffff;
+ d = Math.floor(unsigned / 0xffffffff);
+ unsigned &= 0xffffffff;
+ e = Math.floor(unsigned / 0xffffff);
+ unsigned &= 0xffffff;
+ f = Math.floor(unsigned / 0xffff);
+ unsigned &= 0xffff;
+ g = Math.floor(unsigned / 0xff);
+ unsigned &= 0xff;
+ h = Math.floor(unsigned);
+ return chr(a) + chr(b) + chr(c) + chr(d) + chr(e) + chr(f) + chr(g) + chr(h);
+};
+
+/**
+ * UTF8 methods
+ */
+
+// Take a raw binary string and return a utf8 string
+BinaryParser.decode_utf8 = function decode_utf8 (binaryStr) {
+ var len = binaryStr.length
+ , decoded = ''
+ , i = 0
+ , c = 0
+ , c1 = 0
+ , c2 = 0
+ , c3;
+
+ while (i < len) {
+ c = binaryStr.charCodeAt(i);
+ if (c < 128) {
+ decoded += String.fromCharCode(c);
+ i++;
+ } else if ((c > 191) && (c < 224)) {
+ c2 = binaryStr.charCodeAt(i+1);
+ decoded += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+ i += 2;
+ } else {
+ c2 = binaryStr.charCodeAt(i+1);
+ c3 = binaryStr.charCodeAt(i+2);
+ decoded += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+ i += 3;
+ }
+ }
+
+ return decoded;
+};
+
+// Encode a cstring
+BinaryParser.encode_cstring = function encode_cstring (s) {
+ return unescape(encodeURIComponent(s)) + BinaryParser.fromByte(0);
+};
+
+// Take a utf8 string and return a binary string
+BinaryParser.encode_utf8 = function encode_utf8 (s) {
+ var a = ""
+ , c;
+
+ for (var n = 0, len = s.length; n < len; n++) {
+ c = s.charCodeAt(n);
+
+ if (c < 128) {
+ a += String.fromCharCode(c);
+ } else if ((c > 127) && (c < 2048)) {
+ a += String.fromCharCode((c>>6) | 192) ;
+ a += String.fromCharCode((c&63) | 128);
+ } else {
+ a += String.fromCharCode((c>>12) | 224);
+ a += String.fromCharCode(((c>>6) & 63) | 128);
+ a += String.fromCharCode((c&63) | 128);
+ }
+ }
+
+ return a;
+};
+
+BinaryParser.hprint = function hprint (s) {
+ var number;
+
+ for (var i = 0, len = s.length; i < len; i++) {
+ if (s.charCodeAt(i) < 32) {
+ number = s.charCodeAt(i) <= 15
+ ? "0" + s.charCodeAt(i).toString(16)
+ : s.charCodeAt(i).toString(16);
+ process.stdout.write(number + " ")
+ } else {
+ number = s.charCodeAt(i) <= 15
+ ? "0" + s.charCodeAt(i).toString(16)
+ : s.charCodeAt(i).toString(16);
+ process.stdout.write(number + " ")
+ }
+ }
+
+ process.stdout.write("\n\n");
+};
+
+BinaryParser.ilprint = function hprint (s) {
+ var number;
+
+ for (var i = 0, len = s.length; i < len; i++) {
+ if (s.charCodeAt(i) < 32) {
+ number = s.charCodeAt(i) <= 15
+ ? "0" + s.charCodeAt(i).toString(10)
+ : s.charCodeAt(i).toString(10);
+
+ require('util').debug(number+' : ');
+ } else {
+ number = s.charCodeAt(i) <= 15
+ ? "0" + s.charCodeAt(i).toString(10)
+ : s.charCodeAt(i).toString(10);
+ require('util').debug(number+' : '+ s.charAt(i));
+ }
+ }
+};
+
+BinaryParser.hlprint = function hprint (s) {
+ var number;
+
+ for (var i = 0, len = s.length; i < len; i++) {
+ if (s.charCodeAt(i) < 32) {
+ number = s.charCodeAt(i) <= 15
+ ? "0" + s.charCodeAt(i).toString(16)
+ : s.charCodeAt(i).toString(16);
+ require('util').debug(number+' : ');
+ } else {
+ number = s.charCodeAt(i) <= 15
+ ? "0" + s.charCodeAt(i).toString(16)
+ : s.charCodeAt(i).toString(16);
+ require('util').debug(number+' : '+ s.charAt(i));
+ }
+ }
+};
+
+/**
+ * BinaryParser buffer constructor.
+ */
+function BinaryParserBuffer (bigEndian, buffer) {
+ this.bigEndian = bigEndian || 0;
+ this.buffer = [];
+ this.setBuffer(buffer);
+};
+
+BinaryParserBuffer.prototype.setBuffer = function setBuffer (data) {
+ var l, i, b;
+
+ if (data) {
+ i = l = data.length;
+ b = this.buffer = new Array(l);
+ for (; i; b[l - i] = data.charCodeAt(--i));
+ this.bigEndian && b.reverse();
+ }
+};
+
+BinaryParserBuffer.prototype.hasNeededBits = function hasNeededBits (neededBits) {
+ return this.buffer.length >= -(-neededBits >> 3);
+};
+
+BinaryParserBuffer.prototype.checkBuffer = function checkBuffer (neededBits) {
+ if (!this.hasNeededBits(neededBits)) {
+ throw new Error("checkBuffer::missing bytes");
+ }
+};
+
+BinaryParserBuffer.prototype.readBits = function readBits (start, length) {
+ //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
+
+ function shl (a, b) {
+ for (; b--; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1);
+ return a;
+ }
+
+ if (start < 0 || length <= 0) {
+ return 0;
+ }
+
+ this.checkBuffer(start + length);
+
+ var offsetLeft
+ , offsetRight = start % 8
+ , curByte = this.buffer.length - ( start >> 3 ) - 1
+ , lastByte = this.buffer.length + ( -( start + length ) >> 3 )
+ , diff = curByte - lastByte
+ , sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1)) + (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[lastByte++] & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight : 0);
+
+ for(; diff; sum += shl(this.buffer[lastByte++], (diff-- << 3) - offsetRight));
+
+ return sum;
+};
+
+/**
+ * Expose.
+ */
+BinaryParser.Buffer = BinaryParserBuffer;
+
+exports.BinaryParser = BinaryParser;
+
+},
+
+
+
+'bson': function(module, exports, global, require, undefined){
+ var Long = require('./long').Long
+ , Double = require('./double').Double
+ , Timestamp = require('./timestamp').Timestamp
+ , ObjectID = require('./objectid').ObjectID
+ , Symbol = require('./symbol').Symbol
+ , Code = require('./code').Code
+ , MinKey = require('./min_key').MinKey
+ , MaxKey = require('./max_key').MaxKey
+ , DBRef = require('./db_ref').DBRef
+ , Binary = require('./binary').Binary
+ , BinaryParser = require('./binary_parser').BinaryParser
+ , writeIEEE754 = require('./float_parser').writeIEEE754
+ , readIEEE754 = require('./float_parser').readIEEE754
+
+// To ensure that 0.4 of node works correctly
+var isDate = function isDate(d) {
+ return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]';
+}
+
+/**
+ * Create a new BSON instance
+ *
+ * @class Represents the BSON Parser
+ * @return {BSON} instance of BSON Parser.
+ */
+function BSON () {};
+
+/**
+ * @ignore
+ * @api private
+ */
+// BSON MAX VALUES
+BSON.BSON_INT32_MAX = 0x7FFFFFFF;
+BSON.BSON_INT32_MIN = -0x80000000;
+
+BSON.BSON_INT64_MAX = Math.pow(2, 63) - 1;
+BSON.BSON_INT64_MIN = -Math.pow(2, 63);
+
+// JS MAX PRECISE VALUES
+BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double.
+BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double.
+
+// Internal long versions
+var JS_INT_MAX_LONG = Long.fromNumber(0x20000000000000); // Any integer up to 2^53 can be precisely represented by a double.
+var JS_INT_MIN_LONG = Long.fromNumber(-0x20000000000000); // Any integer down to -2^53 can be precisely represented by a double.
+
+/**
+ * Number BSON Type
+ *
+ * @classconstant BSON_DATA_NUMBER
+ **/
+BSON.BSON_DATA_NUMBER = 1;
+/**
+ * String BSON Type
+ *
+ * @classconstant BSON_DATA_STRING
+ **/
+BSON.BSON_DATA_STRING = 2;
+/**
+ * Object BSON Type
+ *
+ * @classconstant BSON_DATA_OBJECT
+ **/
+BSON.BSON_DATA_OBJECT = 3;
+/**
+ * Array BSON Type
+ *
+ * @classconstant BSON_DATA_ARRAY
+ **/
+BSON.BSON_DATA_ARRAY = 4;
+/**
+ * Binary BSON Type
+ *
+ * @classconstant BSON_DATA_BINARY
+ **/
+BSON.BSON_DATA_BINARY = 5;
+/**
+ * ObjectID BSON Type
+ *
+ * @classconstant BSON_DATA_OID
+ **/
+BSON.BSON_DATA_OID = 7;
+/**
+ * Boolean BSON Type
+ *
+ * @classconstant BSON_DATA_BOOLEAN
+ **/
+BSON.BSON_DATA_BOOLEAN = 8;
+/**
+ * Date BSON Type
+ *
+ * @classconstant BSON_DATA_DATE
+ **/
+BSON.BSON_DATA_DATE = 9;
+/**
+ * null BSON Type
+ *
+ * @classconstant BSON_DATA_NULL
+ **/
+BSON.BSON_DATA_NULL = 10;
+/**
+ * RegExp BSON Type
+ *
+ * @classconstant BSON_DATA_REGEXP
+ **/
+BSON.BSON_DATA_REGEXP = 11;
+/**
+ * Code BSON Type
+ *
+ * @classconstant BSON_DATA_CODE
+ **/
+BSON.BSON_DATA_CODE = 13;
+/**
+ * Symbol BSON Type
+ *
+ * @classconstant BSON_DATA_SYMBOL
+ **/
+BSON.BSON_DATA_SYMBOL = 14;
+/**
+ * Code with Scope BSON Type
+ *
+ * @classconstant BSON_DATA_CODE_W_SCOPE
+ **/
+BSON.BSON_DATA_CODE_W_SCOPE = 15;
+/**
+ * 32 bit Integer BSON Type
+ *
+ * @classconstant BSON_DATA_INT
+ **/
+BSON.BSON_DATA_INT = 16;
+/**
+ * Timestamp BSON Type
+ *
+ * @classconstant BSON_DATA_TIMESTAMP
+ **/
+BSON.BSON_DATA_TIMESTAMP = 17;
+/**
+ * Long BSON Type
+ *
+ * @classconstant BSON_DATA_LONG
+ **/
+BSON.BSON_DATA_LONG = 18;
+/**
+ * MinKey BSON Type
+ *
+ * @classconstant BSON_DATA_MIN_KEY
+ **/
+BSON.BSON_DATA_MIN_KEY = 0xff;
+/**
+ * MaxKey BSON Type
+ *
+ * @classconstant BSON_DATA_MAX_KEY
+ **/
+BSON.BSON_DATA_MAX_KEY = 0x7f;
+
+/**
+ * Binary Default Type
+ *
+ * @classconstant BSON_BINARY_SUBTYPE_DEFAULT
+ **/
+BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
+/**
+ * Binary Function Type
+ *
+ * @classconstant BSON_BINARY_SUBTYPE_FUNCTION
+ **/
+BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1;
+/**
+ * Binary Byte Array Type
+ *
+ * @classconstant BSON_BINARY_SUBTYPE_BYTE_ARRAY
+ **/
+BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
+/**
+ * Binary UUID Type
+ *
+ * @classconstant BSON_BINARY_SUBTYPE_UUID
+ **/
+BSON.BSON_BINARY_SUBTYPE_UUID = 3;
+/**
+ * Binary MD5 Type
+ *
+ * @classconstant BSON_BINARY_SUBTYPE_MD5
+ **/
+BSON.BSON_BINARY_SUBTYPE_MD5 = 4;
+/**
+ * Binary User Defined Type
+ *
+ * @classconstant BSON_BINARY_SUBTYPE_USER_DEFINED
+ **/
+BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
+
+/**
+ * Calculate the bson size for a passed in Javascript object.
+ *
+ * @param {Object} object the Javascript object to calculate the BSON byte size for.
+ * @param {Boolean} [serializeFunctions] serialize all functions in the object **(default:false)**.
+ * @return {Number} returns the number of bytes the BSON object will take up.
+ * @api public
+ */
+BSON.calculateObjectSize = function calculateObjectSize(object, serializeFunctions) {
+ var totalLength = (4 + 1);
+
+ if(Array.isArray(object)) {
+ for(var i = 0; i < object.length; i++) {
+ totalLength += calculateElement(i.toString(), object[i], serializeFunctions)
+ }
+ } else {
+ // If we have toBSON defined, override the current object
+ if(object.toBSON) {
+ object = object.toBSON();
+ }
+
+ // Calculate size
+ for(var key in object) {
+ totalLength += calculateElement(key, object[key], serializeFunctions)
+ }
+ }
+
+ return totalLength;
+}
+
+/**
+ * @ignore
+ * @api private
+ */
+function calculateElement(name, value, serializeFunctions) {
+ var isBuffer = typeof Buffer !== 'undefined';
+
+ switch(typeof value) {
+ case 'string':
+ return 1 + (!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1 + 4 + (!isBuffer ? numberOfBytes(value) : Buffer.byteLength(value, 'utf8')) + 1;
+ case 'number':
+ if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) {
+ if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) { // 32 bit
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (4 + 1);
+ } else {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1);
+ }
+ } else { // 64 bit
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1);
+ }
+ case 'undefined':
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1);
+ case 'boolean':
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1 + 1);
+ case 'object':
+ if(value == null || value instanceof MinKey || value instanceof MaxKey || value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1);
+ } else if(value instanceof ObjectID || value['_bsontype'] == 'ObjectID') {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (12 + 1);
+ } else if(value instanceof Date || isDate(value)) {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1);
+ } else if(typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (1 + 4 + 1) + value.length;
+ } else if(value instanceof Long || value instanceof Double || value instanceof Timestamp
+ || value['_bsontype'] == 'Long' || value['_bsontype'] == 'Double' || value['_bsontype'] == 'Timestamp') {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (8 + 1);
+ } else if(value instanceof Code || value['_bsontype'] == 'Code') {
+ // Calculate size depending on the availability of a scope
+ if(value.scope != null && Object.keys(value.scope).length > 0) {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + 4 + (!isBuffer ? numberOfBytes(value.code.toString()) : Buffer.byteLength(value.code.toString(), 'utf8')) + 1 + BSON.calculateObjectSize(value.scope, serializeFunctions);
+ } else {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + (!isBuffer ? numberOfBytes(value.code.toString()) : Buffer.byteLength(value.code.toString(), 'utf8')) + 1;
+ }
+ } else if(value instanceof Binary || value['_bsontype'] == 'Binary') {
+ // Check what kind of subtype we have
+ if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (value.position + 1 + 4 + 1 + 4);
+ } else {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + (value.position + 1 + 4 + 1);
+ }
+ } else if(value instanceof Symbol || value['_bsontype'] == 'Symbol') {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + ((!isBuffer ? numberOfBytes(value.value) : Buffer.byteLength(value.value, 'utf8')) + 4 + 1 + 1);
+ } else if(value instanceof DBRef || value['_bsontype'] == 'DBRef') {
+ // Set up correct object for serialization
+ var ordered_values = {
+ '$ref': value.namespace
+ , '$id' : value.oid
+ };
+
+ // Add db reference if it exists
+ if(null != value.db) {
+ ordered_values['$db'] = value.db;
+ }
+
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + BSON.calculateObjectSize(ordered_values, serializeFunctions);
+ } else if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]') {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + (!isBuffer ? numberOfBytes(value.source) : Buffer.byteLength(value.source, 'utf8')) + 1
+ + (value.global ? 1 : 0) + (value.ignoreCase ? 1 : 0) + (value.multiline ? 1 : 0) + 1
+ } else {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + BSON.calculateObjectSize(value, serializeFunctions) + 1;
+ }
+ case 'function':
+ // WTF for 0.4.X where typeof /someregexp/ === 'function'
+ if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]' || String.call(value) == '[object RegExp]') {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + (!isBuffer ? numberOfBytes(value.source) : Buffer.byteLength(value.source, 'utf8')) + 1
+ + (value.global ? 1 : 0) + (value.ignoreCase ? 1 : 0) + (value.multiline ? 1 : 0) + 1
+ } else {
+ if(serializeFunctions && value.scope != null && Object.keys(value.scope).length > 0) {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + 4 + (!isBuffer ? numberOfBytes(value.toString()) : Buffer.byteLength(value.toString(), 'utf8')) + 1 + BSON.calculateObjectSize(value.scope, serializeFunctions);
+ } else if(serializeFunctions) {
+ return (name != null ? ((!isBuffer ? numberOfBytes(name) : Buffer.byteLength(name, 'utf8')) + 1) : 0) + 1 + 4 + (!isBuffer ? numberOfBytes(value.toString()) : Buffer.byteLength(value.toString(), 'utf8')) + 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Serialize a Javascript object using a predefined Buffer and index into the buffer, useful when pre-allocating the space for serialization.
+ *
+ * @param {Object} object the Javascript object to serialize.
+ * @param {Boolean} checkKeys the serializer will check if keys are valid.
+ * @param {Buffer} buffer the Buffer you pre-allocated to store the serialized BSON object.
+ * @param {Number} index the index in the buffer where we wish to start serializing into.
+ * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**.
+ * @return {Number} returns the new write index in the Buffer.
+ * @api public
+ */
+BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, checkKeys, buffer, index, serializeFunctions) {
+ // Default setting false
+ serializeFunctions = serializeFunctions == null ? false : serializeFunctions;
+ // Write end information (length of the object)
+ var size = buffer.length;
+ // Write the size of the object
+ buffer[index++] = size & 0xff;
+ buffer[index++] = (size >> 8) & 0xff;
+ buffer[index++] = (size >> 16) & 0xff;
+ buffer[index++] = (size >> 24) & 0xff;
+ return serializeObject(object, checkKeys, buffer, index, serializeFunctions) - 1;
+}
+
+/**
+ * @ignore
+ * @api private
+ */
+var serializeObject = function(object, checkKeys, buffer, index, serializeFunctions) {
+ // Process the object
+ if(Array.isArray(object)) {
+ for(var i = 0; i < object.length; i++) {
+ index = packElement(i.toString(), object[i], checkKeys, buffer, index, serializeFunctions);
+ }
+ } else {
+ // If we have toBSON defined, override the current object
+ if(object.toBSON) {
+ object = object.toBSON();
+ }
+
+ // Serialize the object
+ for(var key in object) {
+ // Check the key and throw error if it's illegal
+ if(checkKeys == true && (key != '$db' && key != '$ref' && key != '$id')) {
+ BSON.checkKey(key);
+ }
+
+ // Pack the element
+ index = packElement(key, object[key], checkKeys, buffer, index, serializeFunctions);
+ }
+ }
+
+ // Write zero
+ buffer[index++] = 0;
+ return index;
+}
+
+var stringToBytes = function(str) {
+ var ch, st, re = [];
+ for (var i = 0; i < str.length; i++ ) {
+ ch = str.charCodeAt(i); // get char
+ st = []; // set up "stack"
+ do {
+ st.push( ch & 0xFF ); // push byte to stack
+ ch = ch >> 8; // shift value down by 1 byte
+ }
+ while ( ch );
+ // add stack contents to result
+ // done because chars have "wrong" endianness
+ re = re.concat( st.reverse() );
+ }
+ // return an array of bytes
+ return re;
+}
+
+var numberOfBytes = function(str) {
+ var ch, st, re = 0;
+ for (var i = 0; i < str.length; i++ ) {
+ ch = str.charCodeAt(i); // get char
+ st = []; // set up "stack"
+ do {
+ st.push( ch & 0xFF ); // push byte to stack
+ ch = ch >> 8; // shift value down by 1 byte
+ }
+ while ( ch );
+ // add stack contents to result
+ // done because chars have "wrong" endianness
+ re = re + st.length;
+ }
+ // return an array of bytes
+ return re;
+}
+
+/**
+ * @ignore
+ * @api private
+ */
+var writeToTypedArray = function(buffer, string, index) {
+ var bytes = stringToBytes(string);
+ for(var i = 0; i < bytes.length; i++) {
+ buffer[index + i] = bytes[i];
+ }
+ return bytes.length;
+}
+
+/**
+ * @ignore
+ * @api private
+ */
+var supportsBuffer = typeof Buffer != 'undefined';
+
+/**
+ * @ignore
+ * @api private
+ */
+var packElement = function(name, value, checkKeys, buffer, index, serializeFunctions) {
+ var startIndex = index;
+
+ switch(typeof value) {
+ case 'string':
+ // Encode String type
+ buffer[index++] = BSON.BSON_DATA_STRING;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+
+ // Calculate size
+ var size = supportsBuffer ? Buffer.byteLength(value) + 1 : numberOfBytes(value) + 1;
+ // Write the size of the string to buffer
+ buffer[index + 3] = (size >> 24) & 0xff;
+ buffer[index + 2] = (size >> 16) & 0xff;
+ buffer[index + 1] = (size >> 8) & 0xff;
+ buffer[index] = size & 0xff;
+ // Ajust the index
+ index = index + 4;
+ // Write the string
+ supportsBuffer ? buffer.write(value, index, 'utf8') : writeToTypedArray(buffer, value, index);
+ // Update index
+ index = index + size - 1;
+ // Write zero
+ buffer[index++] = 0;
+ // Return index
+ return index;
+ case 'number':
+ // We have an integer value
+ if(Math.floor(value) === value && value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) {
+ // If the value fits in 32 bits encode as int, if it fits in a double
+ // encode it as a double, otherwise long
+ if(value >= BSON.BSON_INT32_MIN && value <= BSON.BSON_INT32_MAX) {
+ // Set int type 32 bits or less
+ buffer[index++] = BSON.BSON_DATA_INT;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Write the int value
+ buffer[index++] = value & 0xff;
+ buffer[index++] = (value >> 8) & 0xff;
+ buffer[index++] = (value >> 16) & 0xff;
+ buffer[index++] = (value >> 24) & 0xff;
+ } else if(value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) {
+ // Encode as double
+ buffer[index++] = BSON.BSON_DATA_NUMBER;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Write float
+ writeIEEE754(buffer, value, index, 'little', 52, 8);
+ // Ajust index
+ index = index + 8;
+ } else {
+ // Set long type
+ buffer[index++] = BSON.BSON_DATA_LONG;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ var longVal = Long.fromNumber(value);
+ var lowBits = longVal.getLowBits();
+ var highBits = longVal.getHighBits();
+ // Encode low bits
+ buffer[index++] = lowBits & 0xff;
+ buffer[index++] = (lowBits >> 8) & 0xff;
+ buffer[index++] = (lowBits >> 16) & 0xff;
+ buffer[index++] = (lowBits >> 24) & 0xff;
+ // Encode high bits
+ buffer[index++] = highBits & 0xff;
+ buffer[index++] = (highBits >> 8) & 0xff;
+ buffer[index++] = (highBits >> 16) & 0xff;
+ buffer[index++] = (highBits >> 24) & 0xff;
+ }
+ } else {
+ // Encode as double
+ buffer[index++] = BSON.BSON_DATA_NUMBER;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Write float
+ writeIEEE754(buffer, value, index, 'little', 52, 8);
+ // Ajust index
+ index = index + 8;
+ }
+
+ return index;
+ case 'undefined':
+ // Set long type
+ buffer[index++] = BSON.BSON_DATA_NULL;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ return index;
+ case 'boolean':
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_BOOLEAN;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Encode the boolean value
+ buffer[index++] = value ? 1 : 0;
+ return index;
+ case 'object':
+ if(value === null || value instanceof MinKey || value instanceof MaxKey
+ || value['_bsontype'] == 'MinKey' || value['_bsontype'] == 'MaxKey') {
+ // Write the type of either min or max key
+ if(value === null) {
+ buffer[index++] = BSON.BSON_DATA_NULL;
+ } else if(value instanceof MinKey) {
+ buffer[index++] = BSON.BSON_DATA_MIN_KEY;
+ } else {
+ buffer[index++] = BSON.BSON_DATA_MAX_KEY;
+ }
+
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ return index;
+ } else if(value instanceof ObjectID || value['_bsontype'] == 'ObjectID') {
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_OID;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+
+ // Write objectid
+ supportsBuffer ? buffer.write(value.id, index, 'binary') : writeToTypedArray(buffer, value.id, index);
+ // Ajust index
+ index = index + 12;
+ return index;
+ } else if(value instanceof Date || isDate(value)) {
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_DATE;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+
+ // Write the date
+ var dateInMilis = Long.fromNumber(value.getTime());
+ var lowBits = dateInMilis.getLowBits();
+ var highBits = dateInMilis.getHighBits();
+ // Encode low bits
+ buffer[index++] = lowBits & 0xff;
+ buffer[index++] = (lowBits >> 8) & 0xff;
+ buffer[index++] = (lowBits >> 16) & 0xff;
+ buffer[index++] = (lowBits >> 24) & 0xff;
+ // Encode high bits
+ buffer[index++] = highBits & 0xff;
+ buffer[index++] = (highBits >> 8) & 0xff;
+ buffer[index++] = (highBits >> 16) & 0xff;
+ buffer[index++] = (highBits >> 24) & 0xff;
+ return index;
+ } else if(typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_BINARY;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Get size of the buffer (current write point)
+ var size = value.length;
+ // Write the size of the string to buffer
+ buffer[index++] = size & 0xff;
+ buffer[index++] = (size >> 8) & 0xff;
+ buffer[index++] = (size >> 16) & 0xff;
+ buffer[index++] = (size >> 24) & 0xff;
+ // Write the default subtype
+ buffer[index++] = BSON.BSON_BINARY_SUBTYPE_DEFAULT;
+ // Copy the content form the binary field to the buffer
+ value.copy(buffer, index, 0, size);
+ // Adjust the index
+ index = index + size;
+ return index;
+ } else if(value instanceof Long || value instanceof Timestamp || value['_bsontype'] == 'Long' || value['_bsontype'] == 'Timestamp') {
+ // Write the type
+ buffer[index++] = value instanceof Long ? BSON.BSON_DATA_LONG : BSON.BSON_DATA_TIMESTAMP;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Write the date
+ var lowBits = value.getLowBits();
+ var highBits = value.getHighBits();
+ // Encode low bits
+ buffer[index++] = lowBits & 0xff;
+ buffer[index++] = (lowBits >> 8) & 0xff;
+ buffer[index++] = (lowBits >> 16) & 0xff;
+ buffer[index++] = (lowBits >> 24) & 0xff;
+ // Encode high bits
+ buffer[index++] = highBits & 0xff;
+ buffer[index++] = (highBits >> 8) & 0xff;
+ buffer[index++] = (highBits >> 16) & 0xff;
+ buffer[index++] = (highBits >> 24) & 0xff;
+ return index;
+ } else if(value instanceof Double || value['_bsontype'] == 'Double') {
+ // Encode as double
+ buffer[index++] = BSON.BSON_DATA_NUMBER;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Write float
+ writeIEEE754(buffer, value, index, 'little', 52, 8);
+ // Ajust index
+ index = index + 8;
+ return index;
+ } else if(value instanceof Code || value['_bsontype'] == 'Code') {
+ if(value.scope != null && Object.keys(value.scope).length > 0) {
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Calculate the scope size
+ var scopeSize = BSON.calculateObjectSize(value.scope, serializeFunctions);
+ // Function string
+ var functionString = value.code.toString();
+ // Function Size
+ var codeSize = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1;
+
+ // Calculate full size of the object
+ var totalSize = 4 + codeSize + scopeSize + 4;
+
+ // Write the total size of the object
+ buffer[index++] = totalSize & 0xff;
+ buffer[index++] = (totalSize >> 8) & 0xff;
+ buffer[index++] = (totalSize >> 16) & 0xff;
+ buffer[index++] = (totalSize >> 24) & 0xff;
+
+ // Write the size of the string to buffer
+ buffer[index++] = codeSize & 0xff;
+ buffer[index++] = (codeSize >> 8) & 0xff;
+ buffer[index++] = (codeSize >> 16) & 0xff;
+ buffer[index++] = (codeSize >> 24) & 0xff;
+
+ // Write the string
+ supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index);
+ // Update index
+ index = index + codeSize - 1;
+ // Write zero
+ buffer[index++] = 0;
+ // Serialize the scope object
+ var scopeObjectBuffer = supportsBuffer ? new Buffer(scopeSize) : new Uint8Array(new ArrayBuffer(scopeSize));
+ // Execute the serialization into a seperate buffer
+ serializeObject(value.scope, checkKeys, scopeObjectBuffer, 0, serializeFunctions);
+
+ // Adjusted scope Size (removing the header)
+ var scopeDocSize = scopeSize;
+ // Write scope object size
+ buffer[index++] = scopeDocSize & 0xff;
+ buffer[index++] = (scopeDocSize >> 8) & 0xff;
+ buffer[index++] = (scopeDocSize >> 16) & 0xff;
+ buffer[index++] = (scopeDocSize >> 24) & 0xff;
+
+ // Write the scopeObject into the buffer
+ supportsBuffer ? scopeObjectBuffer.copy(buffer, index, 0, scopeSize) : buffer.set(scopeObjectBuffer, index);
+ // Adjust index, removing the empty size of the doc (5 bytes 0000000005)
+ index = index + scopeDocSize - 5;
+ // Write trailing zero
+ buffer[index++] = 0;
+ return index
+ } else {
+ buffer[index++] = BSON.BSON_DATA_CODE;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Function string
+ var functionString = value.code.toString();
+ // Function Size
+ var size = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1;
+ // Write the size of the string to buffer
+ buffer[index++] = size & 0xff;
+ buffer[index++] = (size >> 8) & 0xff;
+ buffer[index++] = (size >> 16) & 0xff;
+ buffer[index++] = (size >> 24) & 0xff;
+ // Write the string
+ supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index);
+ // Update index
+ index = index + size - 1;
+ // Write zero
+ buffer[index++] = 0;
+ return index;
+ }
+ } else if(value instanceof Binary || value['_bsontype'] == 'Binary') {
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_BINARY;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Extract the buffer
+ var data = value.value(true);
+ // Calculate size
+ var size = value.position;
+ // Write the size of the string to buffer
+ buffer[index++] = size & 0xff;
+ buffer[index++] = (size >> 8) & 0xff;
+ buffer[index++] = (size >> 16) & 0xff;
+ buffer[index++] = (size >> 24) & 0xff;
+ // Write the subtype to the buffer
+ buffer[index++] = value.sub_type;
+
+ // If we have binary type 2 the 4 first bytes are the size
+ if(value.sub_type == Binary.SUBTYPE_BYTE_ARRAY) {
+ buffer[index++] = size & 0xff;
+ buffer[index++] = (size >> 8) & 0xff;
+ buffer[index++] = (size >> 16) & 0xff;
+ buffer[index++] = (size >> 24) & 0xff;
+ }
+
+ // Write the data to the object
+ supportsBuffer ? data.copy(buffer, index, 0, value.position) : buffer.set(data, index);
+ // Ajust index
+ index = index + value.position;
+ return index;
+ } else if(value instanceof Symbol || value['_bsontype'] == 'Symbol') {
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_SYMBOL;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Calculate size
+ var size = supportsBuffer ? Buffer.byteLength(value.value) + 1 : numberOfBytes(value.value) + 1;
+ // Write the size of the string to buffer
+ buffer[index++] = size & 0xff;
+ buffer[index++] = (size >> 8) & 0xff;
+ buffer[index++] = (size >> 16) & 0xff;
+ buffer[index++] = (size >> 24) & 0xff;
+ // Write the string
+ buffer.write(value.value, index, 'utf8');
+ // Update index
+ index = index + size - 1;
+ // Write zero
+ buffer[index++] = 0x00;
+ return index;
+ } else if(value instanceof DBRef || value['_bsontype'] == 'DBRef') {
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_OBJECT;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Set up correct object for serialization
+ var ordered_values = {
+ '$ref': value.namespace
+ , '$id' : value.oid
+ };
+
+ // Add db reference if it exists
+ if(null != value.db) {
+ ordered_values['$db'] = value.db;
+ }
+
+ // Message size
+ var size = BSON.calculateObjectSize(ordered_values, serializeFunctions);
+ // Serialize the object
+ var endIndex = BSON.serializeWithBufferAndIndex(ordered_values, checkKeys, buffer, index, serializeFunctions);
+ // Write the size of the string to buffer
+ buffer[index++] = size & 0xff;
+ buffer[index++] = (size >> 8) & 0xff;
+ buffer[index++] = (size >> 16) & 0xff;
+ buffer[index++] = (size >> 24) & 0xff;
+ // Write zero for object
+ buffer[endIndex++] = 0x00;
+ // Return the end index
+ return endIndex;
+ } else if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]') {
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_REGEXP;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+
+ // Write the regular expression string
+ supportsBuffer ? buffer.write(value.source, index, 'utf8') : writeToTypedArray(buffer, value.source, index);
+ // Adjust the index
+ index = index + (supportsBuffer ? Buffer.byteLength(value.source) : numberOfBytes(value.source));
+ // Write zero
+ buffer[index++] = 0x00;
+ // Write the parameters
+ if(value.global) buffer[index++] = 0x73; // s
+ if(value.ignoreCase) buffer[index++] = 0x69; // i
+ if(value.multiline) buffer[index++] = 0x6d; // m
+ // Add ending zero
+ buffer[index++] = 0x00;
+ return index;
+ } else {
+ // Write the type
+ buffer[index++] = Array.isArray(value) ? BSON.BSON_DATA_ARRAY : BSON.BSON_DATA_OBJECT;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Adjust the index
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ var endIndex = serializeObject(value, checkKeys, buffer, index + 4, serializeFunctions);
+ // Write size
+ var size = endIndex - index;
+ // Write the size of the string to buffer
+ buffer[index++] = size & 0xff;
+ buffer[index++] = (size >> 8) & 0xff;
+ buffer[index++] = (size >> 16) & 0xff;
+ buffer[index++] = (size >> 24) & 0xff;
+ return endIndex;
+ }
+ case 'function':
+ // WTF for 0.4.X where typeof /someregexp/ === 'function'
+ if(value instanceof RegExp || Object.prototype.toString.call(value) === '[object RegExp]' || String.call(value) == '[object RegExp]') {
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_REGEXP;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+
+ // Write the regular expression string
+ buffer.write(value.source, index, 'utf8');
+ // Adjust the index
+ index = index + (supportsBuffer ? Buffer.byteLength(value.source) : numberOfBytes(value.source));
+ // Write zero
+ buffer[index++] = 0x00;
+ // Write the parameters
+ if(value.global) buffer[index++] = 0x73; // s
+ if(value.ignoreCase) buffer[index++] = 0x69; // i
+ if(value.multiline) buffer[index++] = 0x6d; // m
+ // Add ending zero
+ buffer[index++] = 0x00;
+ return index;
+ } else {
+ if(serializeFunctions && value.scope != null && Object.keys(value.scope).length > 0) {
+ // Write the type
+ buffer[index++] = BSON.BSON_DATA_CODE_W_SCOPE;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Calculate the scope size
+ var scopeSize = BSON.calculateObjectSize(value.scope, serializeFunctions);
+ // Function string
+ var functionString = value.toString();
+ // Function Size
+ var codeSize = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1;
+
+ // Calculate full size of the object
+ var totalSize = 4 + codeSize + scopeSize;
+
+ // Write the total size of the object
+ buffer[index++] = totalSize & 0xff;
+ buffer[index++] = (totalSize >> 8) & 0xff;
+ buffer[index++] = (totalSize >> 16) & 0xff;
+ buffer[index++] = (totalSize >> 24) & 0xff;
+
+ // Write the size of the string to buffer
+ buffer[index++] = codeSize & 0xff;
+ buffer[index++] = (codeSize >> 8) & 0xff;
+ buffer[index++] = (codeSize >> 16) & 0xff;
+ buffer[index++] = (codeSize >> 24) & 0xff;
+
+ // Write the string
+ supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index);
+ // Update index
+ index = index + codeSize - 1;
+ // Write zero
+ buffer[index++] = 0;
+ // Serialize the scope object
+ var scopeObjectBuffer = new Buffer(scopeSize);
+ // Execute the serialization into a seperate buffer
+ serializeObject(value.scope, checkKeys, scopeObjectBuffer, 0, serializeFunctions);
+
+ // Adjusted scope Size (removing the header)
+ var scopeDocSize = scopeSize - 4;
+ // Write scope object size
+ buffer[index++] = scopeDocSize & 0xff;
+ buffer[index++] = (scopeDocSize >> 8) & 0xff;
+ buffer[index++] = (scopeDocSize >> 16) & 0xff;
+ buffer[index++] = (scopeDocSize >> 24) & 0xff;
+
+ // Write the scopeObject into the buffer
+ scopeObjectBuffer.copy(buffer, index, 0, scopeSize);
+
+ // Adjust index, removing the empty size of the doc (5 bytes 0000000005)
+ index = index + scopeDocSize - 5;
+ // Write trailing zero
+ buffer[index++] = 0;
+ return index
+ } else if(serializeFunctions) {
+ buffer[index++] = BSON.BSON_DATA_CODE;
+ // Number of written bytes
+ var numberOfWrittenBytes = supportsBuffer ? buffer.write(name, index, 'utf8') : writeToTypedArray(buffer, name, index);
+ // Encode the name
+ index = index + numberOfWrittenBytes + 1;
+ buffer[index - 1] = 0;
+ // Function string
+ var functionString = value.toString();
+ // Function Size
+ var size = supportsBuffer ? Buffer.byteLength(functionString) + 1 : numberOfBytes(functionString) + 1;
+ // Write the size of the string to buffer
+ buffer[index++] = size & 0xff;
+ buffer[index++] = (size >> 8) & 0xff;
+ buffer[index++] = (size >> 16) & 0xff;
+ buffer[index++] = (size >> 24) & 0xff;
+ // Write the string
+ supportsBuffer ? buffer.write(functionString, index, 'utf8') : writeToTypedArray(buffer, functionString, index);
+ // Update index
+ index = index + size - 1;
+ // Write zero
+ buffer[index++] = 0;
+ return index;
+ }
+ }
+ }
+
+ // If no value to serialize
+ return index;
+}
+
+/**
+ * Serialize a Javascript object.
+ *
+ * @param {Object} object the Javascript object to serialize.
+ * @param {Boolean} checkKeys the serializer will check if keys are valid.
+ * @param {Boolean} asBuffer return the serialized object as a Buffer object **(ignore)**.
+ * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**.
+ * @return {Buffer} returns the Buffer object containing the serialized object.
+ * @api public
+ */
+BSON.serialize = function(object, checkKeys, asBuffer, serializeFunctions) {
+ var buffer = null;
+ // Calculate the size of the object
+ var size = BSON.calculateObjectSize(object, serializeFunctions);
+ // Fetch the best available type for storing the binary data
+ if(buffer = typeof Buffer != 'undefined') {
+ buffer = new Buffer(size);
+ asBuffer = true;
+ } else if(typeof Uint8Array != 'undefined') {
+ buffer = new Uint8Array(new ArrayBuffer(size));
+ } else {
+ buffer = new Array(size);
+ }
+
+ // If asBuffer is false use typed arrays
+ BSON.serializeWithBufferAndIndex(object, checkKeys, buffer, 0, serializeFunctions);
+ return buffer;
+}
+
+/**
+ * Contains the function cache if we have that enable to allow for avoiding the eval step on each deserialization, comparison is by md5
+ *
+ * @ignore
+ * @api private
+ */
+var functionCache = BSON.functionCache = {};
+
+/**
+ * Crc state variables shared by function
+ *
+ * @ignore
+ * @api private
+ */
+var table = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D];
+
+/**
+ * CRC32 hash method, Fast and enough versitility for our usage
+ *
+ * @ignore
+ * @api private
+ */
+var crc32 = function(string, start, end) {
+ var crc = 0
+ var x = 0;
+ var y = 0;
+ crc = crc ^ (-1);
+
+ for(var i = start, iTop = end; i < iTop;i++) {
+ y = (crc ^ string[i]) & 0xFF;
+ x = table[y];
+ crc = (crc >>> 8) ^ x;
+ }
+
+ return crc ^ (-1);
+}
+
+/**
+ * Deserialize stream data as BSON documents.
+ *
+ * Options
+ * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized.
+ * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse.
+ * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function.
+ *
+ * @param {Buffer} data the buffer containing the serialized set of BSON documents.
+ * @param {Number} startIndex the start index in the data Buffer where the deserialization is to start.
+ * @param {Number} numberOfDocuments number of documents to deserialize.
+ * @param {Array} documents an array where to store the deserialized documents.
+ * @param {Number} docStartIndex the index in the documents array from where to start inserting documents.
+ * @param {Object} [options] additional options used for the deserialization.
+ * @return {Number} returns the next index in the buffer after deserialization **x** numbers of documents.
+ * @api public
+ */
+BSON.deserializeStream = function(data, startIndex, numberOfDocuments, documents, docStartIndex, options) {
+ // if(numberOfDocuments !== documents.length) throw new Error("Number of expected results back is less than the number of documents");
+ options = options != null ? options : {};
+ var index = startIndex;
+ // Loop over all documents
+ for(var i = 0; i < numberOfDocuments; i++) {
+ // Find size of the document
+ var size = data[index] | data[index + 1] << 8 | data[index + 2] << 16 | data[index + 3] << 24;
+ // Update options with index
+ options['index'] = index;
+ // Parse the document at this point
+ documents[docStartIndex + i] = BSON.deserialize(data, options);
+ // Adjust index by the document size
+ index = index + size;
+ }
+
+ // Return object containing end index of parsing and list of documents
+ return index;
+}
+
+/**
+ * Ensure eval is isolated.
+ *
+ * @ignore
+ * @api private
+ */
+var isolateEvalWithHash = function(functionCache, hash, functionString, object) {
+ // Contains the value we are going to set
+ var value = null;
+
+ // Check for cache hit, eval if missing and return cached function
+ if(functionCache[hash] == null) {
+ eval("value = " + functionString);
+ functionCache[hash] = value;
+ }
+ // Set the object
+ return functionCache[hash].bind(object);
+}
+
+/**
+ * Ensure eval is isolated.
+ *
+ * @ignore
+ * @api private
+ */
+var isolateEval = function(functionString) {
+ // Contains the value we are going to set
+ var value = null;
+ // Eval the function
+ eval("value = " + functionString);
+ return value;
+}
+
+/**
+ * Convert Uint8Array to String
+ *
+ * @ignore
+ * @api private
+ */
+var convertUint8ArrayToUtf8String = function(byteArray, startIndex, endIndex) {
+ return BinaryParser.decode_utf8(convertArraytoUtf8BinaryString(byteArray, startIndex, endIndex));
+}
+
+var convertArraytoUtf8BinaryString = function(byteArray, startIndex, endIndex) {
+ var result = "";
+ for(var i = startIndex; i < endIndex; i++) {
+ result = result + String.fromCharCode(byteArray[i]);
+ }
+
+ return result;
+};
+
+/**
+ * Deserialize data as BSON.
+ *
+ * Options
+ * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized.
+ * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse.
+ * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function.
+ *
+ * @param {Buffer} buffer the buffer containing the serialized set of BSON documents.
+ * @param {Object} [options] additional options used for the deserialization.
+ * @param {Boolean} [isArray] ignore used for recursive parsing.
+ * @return {Object} returns the deserialized Javascript Object.
+ * @api public
+ */
+BSON.deserialize = function(buffer, options, isArray) {
+ // Options
+ options = options == null ? {} : options;
+ var evalFunctions = options['evalFunctions'] == null ? false : options['evalFunctions'];
+ var cacheFunctions = options['cacheFunctions'] == null ? false : options['cacheFunctions'];
+ var cacheFunctionsCrc32 = options['cacheFunctionsCrc32'] == null ? false : options['cacheFunctionsCrc32'];
+
+ // Validate that we have at least 4 bytes of buffer
+ if(buffer.length < 5) throw new Error("corrupt bson message < 5 bytes long");
+
+ // Set up index
+ var index = typeof options['index'] == 'number' ? options['index'] : 0;
+ // Reads in a C style string
+ var readCStyleString = function() {
+ // Get the start search index
+ var i = index;
+ // Locate the end of the c string
+ while(buffer[i] !== 0x00) { i++ }
+ // Grab utf8 encoded string
+ var string = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, i) : convertUint8ArrayToUtf8String(buffer, index, i);
+ // Update index position
+ index = i + 1;
+ // Return string
+ return string;
+ }
+
+ // Create holding object
+ var object = isArray ? [] : {};
+
+ // Read the document size
+ var size = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+
+ // Ensure buffer is valid size
+ if(size < 5 || size > buffer.length) throw new Error("corrupt bson message");
+
+ // While we have more left data left keep parsing
+ while(true) {
+ // Read the type
+ var elementType = buffer[index++];
+ // If we get a zero it's the last byte, exit
+ if(elementType == 0) break;
+ // Read the name of the field
+ var name = readCStyleString();
+ // Switch on the type
+ switch(elementType) {
+ case BSON.BSON_DATA_OID:
+ var string = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('binary', index, index + 12) : convertArraytoUtf8BinaryString(buffer, index, index + 12);
+ // Decode the oid
+ object[name] = new ObjectID(string);
+ // Update index
+ index = index + 12;
+ break;
+ case BSON.BSON_DATA_STRING:
+ // Read the content of the field
+ var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ // Add string to object
+ object[name] = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, index + stringSize - 1) : convertUint8ArrayToUtf8String(buffer, index, index + stringSize - 1);
+ // Update parse index position
+ index = index + stringSize;
+ break;
+ case BSON.BSON_DATA_INT:
+ // Decode the 32bit value
+ object[name] = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ break;
+ case BSON.BSON_DATA_NUMBER:
+ // Decode the double value
+ object[name] = readIEEE754(buffer, index, 'little', 52, 8);
+ // Update the index
+ index = index + 8;
+ break;
+ case BSON.BSON_DATA_DATE:
+ // Unpack the low and high bits
+ var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ // Set date object
+ object[name] = new Date(new Long(lowBits, highBits).toNumber());
+ break;
+ case BSON.BSON_DATA_BOOLEAN:
+ // Parse the boolean value
+ object[name] = buffer[index++] == 1;
+ break;
+ case BSON.BSON_DATA_NULL:
+ // Parse the boolean value
+ object[name] = null;
+ break;
+ case BSON.BSON_DATA_BINARY:
+ // Decode the size of the binary blob
+ var binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ // Decode the subtype
+ var subType = buffer[index++];
+ // Decode as raw Buffer object if options specifies it
+ if(buffer['slice'] != null) {
+ // If we have subtype 2 skip the 4 bytes for the size
+ if(subType == Binary.SUBTYPE_BYTE_ARRAY) {
+ binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ }
+ // Slice the data
+ object[name] = new Binary(buffer.slice(index, index + binarySize), subType);
+ } else {
+ var _buffer = typeof Uint8Array != 'undefined' ? new Uint8Array(new ArrayBuffer(binarySize)) : new Array(binarySize);
+ // If we have subtype 2 skip the 4 bytes for the size
+ if(subType == Binary.SUBTYPE_BYTE_ARRAY) {
+ binarySize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ }
+ // Copy the data
+ for(var i = 0; i < binarySize; i++) {
+ _buffer[i] = buffer[index + i];
+ }
+ // Create the binary object
+ object[name] = new Binary(_buffer, subType);
+ }
+ // Update the index
+ index = index + binarySize;
+ break;
+ case BSON.BSON_DATA_ARRAY:
+ options['index'] = index;
+ // Decode the size of the array document
+ var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24;
+ // Set the array to the object
+ object[name] = BSON.deserialize(buffer, options, true);
+ // Adjust the index
+ index = index + objectSize;
+ break;
+ case BSON.BSON_DATA_OBJECT:
+ options['index'] = index;
+ // Decode the size of the object document
+ var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24;
+ // Set the array to the object
+ object[name] = BSON.deserialize(buffer, options, false);
+ // Adjust the index
+ index = index + objectSize;
+ break;
+ case BSON.BSON_DATA_REGEXP:
+ // Create the regexp
+ var source = readCStyleString();
+ var regExpOptions = readCStyleString();
+ // For each option add the corresponding one for javascript
+ var optionsArray = new Array(regExpOptions.length);
+
+ // Parse options
+ for(var i = 0; i < regExpOptions.length; i++) {
+ switch(regExpOptions[i]) {
+ case 'm':
+ optionsArray[i] = 'm';
+ break;
+ case 's':
+ optionsArray[i] = 'g';
+ break;
+ case 'i':
+ optionsArray[i] = 'i';
+ break;
+ }
+ }
+
+ object[name] = new RegExp(source, optionsArray.join(''));
+ break;
+ case BSON.BSON_DATA_LONG:
+ // Unpack the low and high bits
+ var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ // Create long object
+ var long = new Long(lowBits, highBits);
+ // Set the object
+ object[name] = long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG) ? long.toNumber() : long;
+ break;
+ case BSON.BSON_DATA_SYMBOL:
+ // Read the content of the field
+ var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ // Add string to object
+ object[name] = new Symbol(buffer.toString('utf8', index, index + stringSize - 1));
+ // Update parse index position
+ index = index + stringSize;
+ break;
+ case BSON.BSON_DATA_TIMESTAMP:
+ // Unpack the low and high bits
+ var lowBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ var highBits = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ // Set the object
+ object[name] = new Timestamp(lowBits, highBits);
+ break;
+ case BSON.BSON_DATA_MIN_KEY:
+ // Parse the object
+ object[name] = new MinKey();
+ break;
+ case BSON.BSON_DATA_MAX_KEY:
+ // Parse the object
+ object[name] = new MaxKey();
+ break;
+ case BSON.BSON_DATA_CODE:
+ // Read the content of the field
+ var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ // Function string
+ var functionString = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, index + stringSize - 1) : convertUint8ArrayToUtf8String(buffer, index, index + stringSize - 1);
+
+ // If we are evaluating the functions
+ if(evalFunctions) {
+ // Contains the value we are going to set
+ var value = null;
+ // If we have cache enabled let's look for the md5 of the function in the cache
+ if(cacheFunctions) {
+ var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString;
+ // Got to do this to avoid V8 deoptimizing the call due to finding eval
+ object[name] = isolateEvalWithHash(functionCache, hash, functionString, object);
+ } else {
+ // Set directly
+ object[name] = isolateEval(functionString);
+ }
+ } else {
+ object[name] = new Code(functionString, {});
+ }
+
+ // Update parse index position
+ index = index + stringSize;
+ break;
+ case BSON.BSON_DATA_CODE_W_SCOPE:
+ // Read the content of the field
+ var totalSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ var stringSize = buffer[index++] | buffer[index++] << 8 | buffer[index++] << 16 | buffer[index++] << 24;
+ // Javascript function
+ var functionString = supportsBuffer && Buffer.isBuffer(buffer) ? buffer.toString('utf8', index, index + stringSize - 1) : convertUint8ArrayToUtf8String(buffer, index, index + stringSize - 1);
+ // Update parse index position
+ index = index + stringSize;
+ // Parse the element
+ options['index'] = index;
+ // Decode the size of the object document
+ var objectSize = buffer[index] | buffer[index + 1] << 8 | buffer[index + 2] << 16 | buffer[index + 3] << 24;
+ // Decode the scope object
+ var scopeObject = BSON.deserialize(buffer, options, false);
+ // Adjust the index
+ index = index + objectSize;
+
+ // If we are evaluating the functions
+ if(evalFunctions) {
+ // Contains the value we are going to set
+ var value = null;
+ // If we have cache enabled let's look for the md5 of the function in the cache
+ if(cacheFunctions) {
+ var hash = cacheFunctionsCrc32 ? crc32(functionString) : functionString;
+ // Got to do this to avoid V8 deoptimizing the call due to finding eval
+ object[name] = isolateEvalWithHash(functionCache, hash, functionString, object);
+ } else {
+ // Set directly
+ object[name] = isolateEval(functionString);
+ }
+
+ // Set the scope on the object
+ object[name].scope = scopeObject;
+ } else {
+ object[name] = new Code(functionString, scopeObject);
+ }
+
+ // Add string to object
+ break;
+ }
+ }
+
+ // Check if we have a db ref object
+ if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']);
+
+ // Return the final objects
+ return object;
+}
+
+/**
+ * Check if key name is valid.
+ *
+ * @ignore
+ * @api private
+ */
+BSON.checkKey = function checkKey (key) {
+ if (!key.length) return;
+ // Check if we have a legal key for the object
+ if('$' == key[0]) {
+ throw Error("key " + key + " must not start with '$'");
+ } else if (!!~key.indexOf('.')) {
+ throw Error("key " + key + " must not contain '.'");
+ }
+};
+
+/**
+ * Deserialize data as BSON.
+ *
+ * Options
+ * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized.
+ * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse.
+ * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function.
+ *
+ * @param {Buffer} buffer the buffer containing the serialized set of BSON documents.
+ * @param {Object} [options] additional options used for the deserialization.
+ * @param {Boolean} [isArray] ignore used for recursive parsing.
+ * @return {Object} returns the deserialized Javascript Object.
+ * @api public
+ */
+BSON.prototype.deserialize = function(data, options) {
+ return BSON.deserialize(data, options);
+}
+
+/**
+ * Deserialize stream data as BSON documents.
+ *
+ * Options
+ * - **evalFunctions** {Boolean, default:false}, evaluate functions in the BSON document scoped to the object deserialized.
+ * - **cacheFunctions** {Boolean, default:false}, cache evaluated functions for reuse.
+ * - **cacheFunctionsCrc32** {Boolean, default:false}, use a crc32 code for caching, otherwise use the string of the function.
+ *
+ * @param {Buffer} data the buffer containing the serialized set of BSON documents.
+ * @param {Number} startIndex the start index in the data Buffer where the deserialization is to start.
+ * @param {Number} numberOfDocuments number of documents to deserialize.
+ * @param {Array} documents an array where to store the deserialized documents.
+ * @param {Number} docStartIndex the index in the documents array from where to start inserting documents.
+ * @param {Object} [options] additional options used for the deserialization.
+ * @return {Number} returns the next index in the buffer after deserialization **x** numbers of documents.
+ * @api public
+ */
+BSON.prototype.deserializeStream = function(data, startIndex, numberOfDocuments, documents, docStartIndex, options) {
+ return BSON.deserializeStream(data, startIndex, numberOfDocuments, documents, docStartIndex, options);
+}
+
+/**
+ * Serialize a Javascript object.
+ *
+ * @param {Object} object the Javascript object to serialize.
+ * @param {Boolean} checkKeys the serializer will check if keys are valid.
+ * @param {Boolean} asBuffer return the serialized object as a Buffer object **(ignore)**.
+ * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**.
+ * @return {Buffer} returns the Buffer object containing the serialized object.
+ * @api public
+ */
+BSON.prototype.serialize = function(object, checkKeys, asBuffer, serializeFunctions) {
+ return BSON.serialize(object, checkKeys, asBuffer, serializeFunctions);
+}
+
+/**
+ * Calculate the bson size for a passed in Javascript object.
+ *
+ * @param {Object} object the Javascript object to calculate the BSON byte size for.
+ * @param {Boolean} [serializeFunctions] serialize all functions in the object **(default:false)**.
+ * @return {Number} returns the number of bytes the BSON object will take up.
+ * @api public
+ */
+BSON.prototype.calculateObjectSize = function(object, serializeFunctions) {
+ return BSON.calculateObjectSize(object, serializeFunctions);
+}
+
+/**
+ * Serialize a Javascript object using a predefined Buffer and index into the buffer, useful when pre-allocating the space for serialization.
+ *
+ * @param {Object} object the Javascript object to serialize.
+ * @param {Boolean} checkKeys the serializer will check if keys are valid.
+ * @param {Buffer} buffer the Buffer you pre-allocated to store the serialized BSON object.
+ * @param {Number} index the index in the buffer where we wish to start serializing into.
+ * @param {Boolean} serializeFunctions serialize the javascript functions **(default:false)**.
+ * @return {Number} returns the new write index in the Buffer.
+ * @api public
+ */
+BSON.prototype.serializeWithBufferAndIndex = function(object, checkKeys, buffer, startIndex, serializeFunctions) {
+ return BSON.serializeWithBufferAndIndex(object, checkKeys, buffer, startIndex, serializeFunctions);
+}
+
+/**
+ * @ignore
+ * @api private
+ */
+exports.Code = Code;
+exports.Symbol = Symbol;
+exports.BSON = BSON;
+exports.DBRef = DBRef;
+exports.Binary = Binary;
+exports.ObjectID = ObjectID;
+exports.Long = Long;
+exports.Timestamp = Timestamp;
+exports.Double = Double;
+exports.MinKey = MinKey;
+exports.MaxKey = MaxKey;
+
+},
+
+
+
+'code': function(module, exports, global, require, undefined){
+ /**
+ * A class representation of the BSON Code type.
+ *
+ * @class Represents the BSON Code type.
+ * @param {String|Function} code a string or function.
+ * @param {Object} [scope] an optional scope for the function.
+ * @return {Code}
+ */
+function Code(code, scope) {
+ if(!(this instanceof Code)) return new Code(code, scope);
+
+ this._bsontype = 'Code';
+ this.code = code;
+ this.scope = scope == null ? {} : scope;
+};
+
+/**
+ * @ignore
+ * @api private
+ */
+Code.prototype.toJSON = function() {
+ return {scope:this.scope, code:this.code};
+}
+
+exports.Code = Code;
+},
+
+
+
+'db_ref': function(module, exports, global, require, undefined){
+ /**
+ * A class representation of the BSON DBRef type.
+ *
+ * @class Represents the BSON DBRef type.
+ * @param {String} namespace the collection name.
+ * @param {ObjectID} oid the reference ObjectID.
+ * @param {String} [db] optional db name, if omitted the reference is local to the current db.
+ * @return {DBRef}
+ */
+function DBRef(namespace, oid, db) {
+ if(!(this instanceof DBRef)) return new DBRef(namespace, oid, db);
+
+ this._bsontype = 'DBRef';
+ this.namespace = namespace;
+ this.oid = oid;
+ this.db = db;
+};
+
+/**
+ * @ignore
+ * @api private
+ */
+DBRef.prototype.toJSON = function() {
+ return {
+ '$ref':this.namespace,
+ '$id':this.oid,
+ '$db':this.db == null ? '' : this.db
+ };
+}
+
+exports.DBRef = DBRef;
+},
+
+
+
+'double': function(module, exports, global, require, undefined){
+ /**
+ * A class representation of the BSON Double type.
+ *
+ * @class Represents the BSON Double type.
+ * @param {Number} value the number we want to represent as a double.
+ * @return {Double}
+ */
+function Double(value) {
+ if(!(this instanceof Double)) return new Double(value);
+
+ this._bsontype = 'Double';
+ this.value = value;
+}
+
+/**
+ * Access the number value.
+ *
+ * @return {Number} returns the wrapped double number.
+ * @api public
+ */
+Double.prototype.valueOf = function() {
+ return this.value;
+};
+
+/**
+ * @ignore
+ * @api private
+ */
+Double.prototype.toJSON = function() {
+ return this.value;
+}
+
+exports.Double = Double;
+},
+
+
+
+'float_parser': function(module, exports, global, require, undefined){
+ // Copyright (c) 2008, Fair Oaks Labs, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//
+// Modifications to writeIEEE754 to support negative zeroes made by Brian White
+
+var readIEEE754 = function(buffer, offset, endian, mLen, nBytes) {
+ var e, m,
+ bBE = (endian === 'big'),
+ eLen = nBytes * 8 - mLen - 1,
+ eMax = (1 << eLen) - 1,
+ eBias = eMax >> 1,
+ nBits = -7,
+ i = bBE ? 0 : (nBytes - 1),
+ d = bBE ? 1 : -1,
+ s = buffer[offset + i];
+
+ i += d;
+
+ e = s & ((1 << (-nBits)) - 1);
+ s >>= (-nBits);
+ nBits += eLen;
+ for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
+
+ m = e & ((1 << (-nBits)) - 1);
+ e >>= (-nBits);
+ nBits += mLen;
+ for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
+
+ if (e === 0) {
+ e = 1 - eBias;
+ } else if (e === eMax) {
+ return m ? NaN : ((s ? -1 : 1) * Infinity);
+ } else {
+ m = m + Math.pow(2, mLen);
+ e = e - eBias;
+ }
+ return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
+};
+
+var writeIEEE754 = function(buffer, value, offset, endian, mLen, nBytes) {
+ var e, m, c,
+ bBE = (endian === 'big'),
+ eLen = nBytes * 8 - mLen - 1,
+ eMax = (1 << eLen) - 1,
+ eBias = eMax >> 1,
+ rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
+ i = bBE ? (nBytes-1) : 0,
+ d = bBE ? -1 : 1,
+ s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
+
+ value = Math.abs(value);
+
+ if (isNaN(value) || value === Infinity) {
+ m = isNaN(value) ? 1 : 0;
+ e = eMax;
+ } else {
+ e = Math.floor(Math.log(value) / Math.LN2);
+ if (value * (c = Math.pow(2, -e)) < 1) {
+ e--;
+ c *= 2;
+ }
+ if (e+eBias >= 1) {
+ value += rt / c;
+ } else {
+ value += rt * Math.pow(2, 1 - eBias);
+ }
+ if (value * c >= 2) {
+ e++;
+ c /= 2;
+ }
+
+ if (e + eBias >= eMax) {
+ m = 0;
+ e = eMax;
+ } else if (e + eBias >= 1) {
+ m = (value * c - 1) * Math.pow(2, mLen);
+ e = e + eBias;
+ } else {
+ m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
+ e = 0;
+ }
+ }
+
+ for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
+
+ e = (e << mLen) | m;
+ eLen += mLen;
+ for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
+
+ buffer[offset + i - d] |= s * 128;
+};
+
+exports.readIEEE754 = readIEEE754;
+exports.writeIEEE754 = writeIEEE754;
+},
+
+
+
+'index': function(module, exports, global, require, undefined){
+ try {
+ exports.BSONPure = require('./bson');
+ exports.BSONNative = require('../../ext');
+} catch(err) {
+ // do nothing
+}
+
+[ './binary_parser'
+ , './binary'
+ , './code'
+ , './db_ref'
+ , './double'
+ , './max_key'
+ , './min_key'
+ , './objectid'
+ , './symbol'
+ , './timestamp'
+ , './long'].forEach(function (path) {
+ var module = require('./' + path);
+ for (var i in module) {
+ exports[i] = module[i];
+ }
+});
+
+// Exports all the classes for the NATIVE JS BSON Parser
+exports.native = function() {
+ var classes = {};
+ // Map all the classes
+ [ './binary_parser'
+ , './binary'
+ , './code'
+ , './db_ref'
+ , './double'
+ , './max_key'
+ , './min_key'
+ , './objectid'
+ , './symbol'
+ , './timestamp'
+ , './long'
+ , '../../ext'
+].forEach(function (path) {
+ var module = require('./' + path);
+ for (var i in module) {
+ classes[i] = module[i];
+ }
+ });
+ // Return classes list
+ return classes;
+}
+
+// Exports all the classes for the PURE JS BSON Parser
+exports.pure = function() {
+ var classes = {};
+ // Map all the classes
+ [ './binary_parser'
+ , './binary'
+ , './code'
+ , './db_ref'
+ , './double'
+ , './max_key'
+ , './min_key'
+ , './objectid'
+ , './symbol'
+ , './timestamp'
+ , './long'
+ , '././bson'].forEach(function (path) {
+ var module = require('./' + path);
+ for (var i in module) {
+ classes[i] = module[i];
+ }
+ });
+ // Return classes list
+ return classes;
+}
+
+},
+
+
+
+'long': function(module, exports, global, require, undefined){
+ // Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Copyright 2009 Google Inc. All Rights Reserved
+
+/**
+ * Defines a Long class for representing a 64-bit two's-complement
+ * integer value, which faithfully simulates the behavior of a Java "Long". This
+ * implementation is derived from LongLib in GWT.
+ *
+ * Constructs a 64-bit two's-complement integer, given its low and high 32-bit
+ * values as *signed* integers. See the from* functions below for more
+ * convenient ways of constructing Longs.
+ *
+ * The internal representation of a Long is the two given signed, 32-bit values.
+ * We use 32-bit pieces because these are the size of integers on which
+ * Javascript performs bit-operations. For operations like addition and
+ * multiplication, we split each number into 16-bit pieces, which can easily be
+ * multiplied within Javascript's floating-point representation without overflow
+ * or change in sign.
+ *
+ * In the algorithms below, we frequently reduce the negative case to the
+ * positive case by negating the input(s) and then post-processing the result.
+ * Note that we must ALWAYS check specially whether those values are MIN_VALUE
+ * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as
+ * a positive number, it overflows back into a negative). Not handling this
+ * case would often result in infinite recursion.
+ *
+ * @class Represents the BSON Long type.
+ * @param {Number} low the low (signed) 32 bits of the Long.
+ * @param {Number} high the high (signed) 32 bits of the Long.
+ */
+function Long(low, high) {
+ if(!(this instanceof Long)) return new Long(low, high);
+
+ this._bsontype = 'Long';
+ /**
+ * @type {number}
+ * @api private
+ */
+ this.low_ = low | 0; // force into 32 signed bits.
+
+ /**
+ * @type {number}
+ * @api private
+ */
+ this.high_ = high | 0; // force into 32 signed bits.
+};
+
+/**
+ * Return the int value.
+ *
+ * @return {Number} the value, assuming it is a 32-bit integer.
+ * @api public
+ */
+Long.prototype.toInt = function() {
+ return this.low_;
+};
+
+/**
+ * Return the Number value.
+ *
+ * @return {Number} the closest floating-point representation to this value.
+ * @api public
+ */
+Long.prototype.toNumber = function() {
+ return this.high_ * Long.TWO_PWR_32_DBL_ +
+ this.getLowBitsUnsigned();
+};
+
+/**
+ * Return the JSON value.
+ *
+ * @return {String} the JSON representation.
+ * @api public
+ */
+Long.prototype.toJSON = function() {
+ return this.toString();
+}
+
+/**
+ * Return the String value.
+ *
+ * @param {Number} [opt_radix] the radix in which the text should be written.
+ * @return {String} the textual representation of this value.
+ * @api public
+ */
+Long.prototype.toString = function(opt_radix) {
+ var radix = opt_radix || 10;
+ if (radix < 2 || 36 < radix) {
+ throw Error('radix out of range: ' + radix);
+ }
+
+ if (this.isZero()) {
+ return '0';
+ }
+
+ if (this.isNegative()) {
+ if (this.equals(Long.MIN_VALUE)) {
+ // We need to change the Long value before it can be negated, so we remove
+ // the bottom-most digit in this base and then recurse to do the rest.
+ var radixLong = Long.fromNumber(radix);
+ var div = this.div(radixLong);
+ var rem = div.multiply(radixLong).subtract(this);
+ return div.toString(radix) + rem.toInt().toString(radix);
+ } else {
+ return '-' + this.negate().toString(radix);
+ }
+ }
+
+ // Do several (6) digits each time through the loop, so as to
+ // minimize the calls to the very expensive emulated div.
+ var radixToPower = Long.fromNumber(Math.pow(radix, 6));
+
+ var rem = this;
+ var result = '';
+ while (true) {
+ var remDiv = rem.div(radixToPower);
+ var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt();
+ var digits = intval.toString(radix);
+
+ rem = remDiv;
+ if (rem.isZero()) {
+ return digits + result;
+ } else {
+ while (digits.length < 6) {
+ digits = '0' + digits;
+ }
+ result = '' + digits + result;
+ }
+ }
+};
+
+/**
+ * Return the high 32-bits value.
+ *
+ * @return {Number} the high 32-bits as a signed value.
+ * @api public
+ */
+Long.prototype.getHighBits = function() {
+ return this.high_;
+};
+
+/**
+ * Return the low 32-bits value.
+ *
+ * @return {Number} the low 32-bits as a signed value.
+ * @api public
+ */
+Long.prototype.getLowBits = function() {
+ return this.low_;
+};
+
+/**
+ * Return the low unsigned 32-bits value.
+ *
+ * @return {Number} the low 32-bits as an unsigned value.
+ * @api public
+ */
+Long.prototype.getLowBitsUnsigned = function() {
+ return (this.low_ >= 0) ?
+ this.low_ : Long.TWO_PWR_32_DBL_ + this.low_;
+};
+
+/**
+ * Returns the number of bits needed to represent the absolute value of this Long.
+ *
+ * @return {Number} Returns the number of bits needed to represent the absolute value of this Long.
+ * @api public
+ */
+Long.prototype.getNumBitsAbs = function() {
+ if (this.isNegative()) {
+ if (this.equals(Long.MIN_VALUE)) {
+ return 64;
+ } else {
+ return this.negate().getNumBitsAbs();
+ }
+ } else {
+ var val = this.high_ != 0 ? this.high_ : this.low_;
+ for (var bit = 31; bit > 0; bit--) {
+ if ((val & (1 << bit)) != 0) {
+ break;
+ }
+ }
+ return this.high_ != 0 ? bit + 33 : bit + 1;
+ }
+};
+
+/**
+ * Return whether this value is zero.
+ *
+ * @return {Boolean} whether this value is zero.
+ * @api public
+ */
+Long.prototype.isZero = function() {
+ return this.high_ == 0 && this.low_ == 0;
+};
+
+/**
+ * Return whether this value is negative.
+ *
+ * @return {Boolean} whether this value is negative.
+ * @api public
+ */
+Long.prototype.isNegative = function() {
+ return this.high_ < 0;
+};
+
+/**
+ * Return whether this value is odd.
+ *
+ * @return {Boolean} whether this value is odd.
+ * @api public
+ */
+Long.prototype.isOdd = function() {
+ return (this.low_ & 1) == 1;
+};
+
+/**
+ * Return whether this Long equals the other
+ *
+ * @param {Long} other Long to compare against.
+ * @return {Boolean} whether this Long equals the other
+ * @api public
+ */
+Long.prototype.equals = function(other) {
+ return (this.high_ == other.high_) && (this.low_ == other.low_);
+};
+
+/**
+ * Return whether this Long does not equal the other.
+ *
+ * @param {Long} other Long to compare against.
+ * @return {Boolean} whether this Long does not equal the other.
+ * @api public
+ */
+Long.prototype.notEquals = function(other) {
+ return (this.high_ != other.high_) || (this.low_ != other.low_);
+};
+
+/**
+ * Return whether this Long is less than the other.
+ *
+ * @param {Long} other Long to compare against.
+ * @return {Boolean} whether this Long is less than the other.
+ * @api public
+ */
+Long.prototype.lessThan = function(other) {
+ return this.compare(other) < 0;
+};
+
+/**
+ * Return whether this Long is less than or equal to the other.
+ *
+ * @param {Long} other Long to compare against.
+ * @return {Boolean} whether this Long is less than or equal to the other.
+ * @api public
+ */
+Long.prototype.lessThanOrEqual = function(other) {
+ return this.compare(other) <= 0;
+};
+
+/**
+ * Return whether this Long is greater than the other.
+ *
+ * @param {Long} other Long to compare against.
+ * @return {Boolean} whether this Long is greater than the other.
+ * @api public
+ */
+Long.prototype.greaterThan = function(other) {
+ return this.compare(other) > 0;
+};
+
+/**
+ * Return whether this Long is greater than or equal to the other.
+ *
+ * @param {Long} other Long to compare against.
+ * @return {Boolean} whether this Long is greater than or equal to the other.
+ * @api public
+ */
+Long.prototype.greaterThanOrEqual = function(other) {
+ return this.compare(other) >= 0;
+};
+
+/**
+ * Compares this Long with the given one.
+ *
+ * @param {Long} other Long to compare against.
+ * @return {Boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater.
+ * @api public
+ */
+Long.prototype.compare = function(other) {
+ if (this.equals(other)) {
+ return 0;
+ }
+
+ var thisNeg = this.isNegative();
+ var otherNeg = other.isNegative();
+ if (thisNeg && !otherNeg) {
+ return -1;
+ }
+ if (!thisNeg && otherNeg) {
+ return 1;
+ }
+
+ // at this point, the signs are the same, so subtraction will not overflow
+ if (this.subtract(other).isNegative()) {
+ return -1;
+ } else {
+ return 1;
+ }
+};
+
+/**
+ * The negation of this value.
+ *
+ * @return {Long} the negation of this value.
+ * @api public
+ */
+Long.prototype.negate = function() {
+ if (this.equals(Long.MIN_VALUE)) {
+ return Long.MIN_VALUE;
+ } else {
+ return this.not().add(Long.ONE);
+ }
+};
+
+/**
+ * Returns the sum of this and the given Long.
+ *
+ * @param {Long} other Long to add to this one.
+ * @return {Long} the sum of this and the given Long.
+ * @api public
+ */
+Long.prototype.add = function(other) {
+ // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
+
+ var a48 = this.high_ >>> 16;
+ var a32 = this.high_ & 0xFFFF;
+ var a16 = this.low_ >>> 16;
+ var a00 = this.low_ & 0xFFFF;
+
+ var b48 = other.high_ >>> 16;
+ var b32 = other.high_ & 0xFFFF;
+ var b16 = other.low_ >>> 16;
+ var b00 = other.low_ & 0xFFFF;
+
+ var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+ c00 += a00 + b00;
+ c16 += c00 >>> 16;
+ c00 &= 0xFFFF;
+ c16 += a16 + b16;
+ c32 += c16 >>> 16;
+ c16 &= 0xFFFF;
+ c32 += a32 + b32;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c48 += a48 + b48;
+ c48 &= 0xFFFF;
+ return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
+};
+
+/**
+ * Returns the difference of this and the given Long.
+ *
+ * @param {Long} other Long to subtract from this.
+ * @return {Long} the difference of this and the given Long.
+ * @api public
+ */
+Long.prototype.subtract = function(other) {
+ return this.add(other.negate());
+};
+
+/**
+ * Returns the product of this and the given Long.
+ *
+ * @param {Long} other Long to multiply with this.
+ * @return {Long} the product of this and the other.
+ * @api public
+ */
+Long.prototype.multiply = function(other) {
+ if (this.isZero()) {
+ return Long.ZERO;
+ } else if (other.isZero()) {
+ return Long.ZERO;
+ }
+
+ if (this.equals(Long.MIN_VALUE)) {
+ return other.isOdd() ? Long.MIN_VALUE : Long.ZERO;
+ } else if (other.equals(Long.MIN_VALUE)) {
+ return this.isOdd() ? Long.MIN_VALUE : Long.ZERO;
+ }
+
+ if (this.isNegative()) {
+ if (other.isNegative()) {
+ return this.negate().multiply(other.negate());
+ } else {
+ return this.negate().multiply(other).negate();
+ }
+ } else if (other.isNegative()) {
+ return this.multiply(other.negate()).negate();
+ }
+
+ // If both Longs are small, use float multiplication
+ if (this.lessThan(Long.TWO_PWR_24_) &&
+ other.lessThan(Long.TWO_PWR_24_)) {
+ return Long.fromNumber(this.toNumber() * other.toNumber());
+ }
+
+ // Divide each Long into 4 chunks of 16 bits, and then add up 4x4 products.
+ // We can skip products that would overflow.
+
+ var a48 = this.high_ >>> 16;
+ var a32 = this.high_ & 0xFFFF;
+ var a16 = this.low_ >>> 16;
+ var a00 = this.low_ & 0xFFFF;
+
+ var b48 = other.high_ >>> 16;
+ var b32 = other.high_ & 0xFFFF;
+ var b16 = other.low_ >>> 16;
+ var b00 = other.low_ & 0xFFFF;
+
+ var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+ c00 += a00 * b00;
+ c16 += c00 >>> 16;
+ c00 &= 0xFFFF;
+ c16 += a16 * b00;
+ c32 += c16 >>> 16;
+ c16 &= 0xFFFF;
+ c16 += a00 * b16;
+ c32 += c16 >>> 16;
+ c16 &= 0xFFFF;
+ c32 += a32 * b00;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c32 += a16 * b16;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c32 += a00 * b32;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
+ c48 &= 0xFFFF;
+ return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
+};
+
+/**
+ * Returns this Long divided by the given one.
+ *
+ * @param {Long} other Long by which to divide.
+ * @return {Long} this Long divided by the given one.
+ * @api public
+ */
+Long.prototype.div = function(other) {
+ if (other.isZero()) {
+ throw Error('division by zero');
+ } else if (this.isZero()) {
+ return Long.ZERO;
+ }
+
+ if (this.equals(Long.MIN_VALUE)) {
+ if (other.equals(Long.ONE) ||
+ other.equals(Long.NEG_ONE)) {
+ return Long.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE
+ } else if (other.equals(Long.MIN_VALUE)) {
+ return Long.ONE;
+ } else {
+ // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
+ var halfThis = this.shiftRight(1);
+ var approx = halfThis.div(other).shiftLeft(1);
+ if (approx.equals(Long.ZERO)) {
+ return other.isNegative() ? Long.ONE : Long.NEG_ONE;
+ } else {
+ var rem = this.subtract(other.multiply(approx));
+ var result = approx.add(rem.div(other));
+ return result;
+ }
+ }
+ } else if (other.equals(Long.MIN_VALUE)) {
+ return Long.ZERO;
+ }
+
+ if (this.isNegative()) {
+ if (other.isNegative()) {
+ return this.negate().div(other.negate());
+ } else {
+ return this.negate().div(other).negate();
+ }
+ } else if (other.isNegative()) {
+ return this.div(other.negate()).negate();
+ }
+
+ // Repeat the following until the remainder is less than other: find a
+ // floating-point that approximates remainder / other *from below*, add this
+ // into the result, and subtract it from the remainder. It is critical that
+ // the approximate value is less than or equal to the real value so that the
+ // remainder never becomes negative.
+ var res = Long.ZERO;
+ var rem = this;
+ while (rem.greaterThanOrEqual(other)) {
+ // Approximate the result of division. This may be a little greater or
+ // smaller than the actual value.
+ var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));
+
+ // We will tweak the approximate result by changing it in the 48-th digit or
+ // the smallest non-fractional digit, whichever is larger.
+ var log2 = Math.ceil(Math.log(approx) / Math.LN2);
+ var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);
+
+ // Decrease the approximation until it is smaller than the remainder. Note
+ // that if it is too large, the product overflows and is negative.
+ var approxRes = Long.fromNumber(approx);
+ var approxRem = approxRes.multiply(other);
+ while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
+ approx -= delta;
+ approxRes = Long.fromNumber(approx);
+ approxRem = approxRes.multiply(other);
+ }
+
+ // We know the answer can't be zero... and actually, zero would cause
+ // infinite recursion since we would make no progress.
+ if (approxRes.isZero()) {
+ approxRes = Long.ONE;
+ }
+
+ res = res.add(approxRes);
+ rem = rem.subtract(approxRem);
+ }
+ return res;
+};
+
+/**
+ * Returns this Long modulo the given one.
+ *
+ * @param {Long} other Long by which to mod.
+ * @return {Long} this Long modulo the given one.
+ * @api public
+ */
+Long.prototype.modulo = function(other) {
+ return this.subtract(this.div(other).multiply(other));
+};
+
+/**
+ * The bitwise-NOT of this value.
+ *
+ * @return {Long} the bitwise-NOT of this value.
+ * @api public
+ */
+Long.prototype.not = function() {
+ return Long.fromBits(~this.low_, ~this.high_);
+};
+
+/**
+ * Returns the bitwise-AND of this Long and the given one.
+ *
+ * @param {Long} other the Long with which to AND.
+ * @return {Long} the bitwise-AND of this and the other.
+ * @api public
+ */
+Long.prototype.and = function(other) {
+ return Long.fromBits(this.low_ & other.low_, this.high_ & other.high_);
+};
+
+/**
+ * Returns the bitwise-OR of this Long and the given one.
+ *
+ * @param {Long} other the Long with which to OR.
+ * @return {Long} the bitwise-OR of this and the other.
+ * @api public
+ */
+Long.prototype.or = function(other) {
+ return Long.fromBits(this.low_ | other.low_, this.high_ | other.high_);
+};
+
+/**
+ * Returns the bitwise-XOR of this Long and the given one.
+ *
+ * @param {Long} other the Long with which to XOR.
+ * @return {Long} the bitwise-XOR of this and the other.
+ * @api public
+ */
+Long.prototype.xor = function(other) {
+ return Long.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_);
+};
+
+/**
+ * Returns this Long with bits shifted to the left by the given amount.
+ *
+ * @param {Number} numBits the number of bits by which to shift.
+ * @return {Long} this shifted to the left by the given amount.
+ * @api public
+ */
+Long.prototype.shiftLeft = function(numBits) {
+ numBits &= 63;
+ if (numBits == 0) {
+ return this;
+ } else {
+ var low = this.low_;
+ if (numBits < 32) {
+ var high = this.high_;
+ return Long.fromBits(
+ low << numBits,
+ (high << numBits) | (low >>> (32 - numBits)));
+ } else {
+ return Long.fromBits(0, low << (numBits - 32));
+ }
+ }
+};
+
+/**
+ * Returns this Long with bits shifted to the right by the given amount.
+ *
+ * @param {Number} numBits the number of bits by which to shift.
+ * @return {Long} this shifted to the right by the given amount.
+ * @api public
+ */
+Long.prototype.shiftRight = function(numBits) {
+ numBits &= 63;
+ if (numBits == 0) {
+ return this;
+ } else {
+ var high = this.high_;
+ if (numBits < 32) {
+ var low = this.low_;
+ return Long.fromBits(
+ (low >>> numBits) | (high << (32 - numBits)),
+ high >> numBits);
+ } else {
+ return Long.fromBits(
+ high >> (numBits - 32),
+ high >= 0 ? 0 : -1);
+ }
+ }
+};
+
+/**
+ * Returns this Long with bits shifted to the right by the given amount, with the new top bits matching the current sign bit.
+ *
+ * @param {Number} numBits the number of bits by which to shift.
+ * @return {Long} this shifted to the right by the given amount, with zeros placed into the new leading bits.
+ * @api public
+ */
+Long.prototype.shiftRightUnsigned = function(numBits) {
+ numBits &= 63;
+ if (numBits == 0) {
+ return this;
+ } else {
+ var high = this.high_;
+ if (numBits < 32) {
+ var low = this.low_;
+ return Long.fromBits(
+ (low >>> numBits) | (high << (32 - numBits)),
+ high >>> numBits);
+ } else if (numBits == 32) {
+ return Long.fromBits(high, 0);
+ } else {
+ return Long.fromBits(high >>> (numBits - 32), 0);
+ }
+ }
+};
+
+/**
+ * Returns a Long representing the given (32-bit) integer value.
+ *
+ * @param {Number} value the 32-bit integer in question.
+ * @return {Long} the corresponding Long value.
+ * @api public
+ */
+Long.fromInt = function(value) {
+ if (-128 <= value && value < 128) {
+ var cachedObj = Long.INT_CACHE_[value];
+ if (cachedObj) {
+ return cachedObj;
+ }
+ }
+
+ var obj = new Long(value | 0, value < 0 ? -1 : 0);
+ if (-128 <= value && value < 128) {
+ Long.INT_CACHE_[value] = obj;
+ }
+ return obj;
+};
+
+/**
+ * Returns a Long representing the given value, provided that it is a finite number. Otherwise, zero is returned.
+ *
+ * @param {Number} value the number in question.
+ * @return {Long} the corresponding Long value.
+ * @api public
+ */
+Long.fromNumber = function(value) {
+ if (isNaN(value) || !isFinite(value)) {
+ return Long.ZERO;
+ } else if (value <= -Long.TWO_PWR_63_DBL_) {
+ return Long.MIN_VALUE;
+ } else if (value + 1 >= Long.TWO_PWR_63_DBL_) {
+ return Long.MAX_VALUE;
+ } else if (value < 0) {
+ return Long.fromNumber(-value).negate();
+ } else {
+ return new Long(
+ (value % Long.TWO_PWR_32_DBL_) | 0,
+ (value / Long.TWO_PWR_32_DBL_) | 0);
+ }
+};
+
+/**
+ * Returns a Long representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits.
+ *
+ * @param {Number} lowBits the low 32-bits.
+ * @param {Number} highBits the high 32-bits.
+ * @return {Long} the corresponding Long value.
+ * @api public
+ */
+Long.fromBits = function(lowBits, highBits) {
+ return new Long(lowBits, highBits);
+};
+
+/**
+ * Returns a Long representation of the given string, written using the given radix.
+ *
+ * @param {String} str the textual representation of the Long.
+ * @param {Number} opt_radix the radix in which the text is written.
+ * @return {Long} the corresponding Long value.
+ * @api public
+ */
+Long.fromString = function(str, opt_radix) {
+ if (str.length == 0) {
+ throw Error('number format error: empty string');
+ }
+
+ var radix = opt_radix || 10;
+ if (radix < 2 || 36 < radix) {
+ throw Error('radix out of range: ' + radix);
+ }
+
+ if (str.charAt(0) == '-') {
+ return Long.fromString(str.substring(1), radix).negate();
+ } else if (str.indexOf('-') >= 0) {
+ throw Error('number format error: interior "-" character: ' + str);
+ }
+
+ // Do several (8) digits each time through the loop, so as to
+ // minimize the calls to the very expensive emulated div.
+ var radixToPower = Long.fromNumber(Math.pow(radix, 8));
+
+ var result = Long.ZERO;
+ for (var i = 0; i < str.length; i += 8) {
+ var size = Math.min(8, str.length - i);
+ var value = parseInt(str.substring(i, i + size), radix);
+ if (size < 8) {
+ var power = Long.fromNumber(Math.pow(radix, size));
+ result = result.multiply(power).add(Long.fromNumber(value));
+ } else {
+ result = result.multiply(radixToPower);
+ result = result.add(Long.fromNumber(value));
+ }
+ }
+ return result;
+};
+
+// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
+// from* methods on which they depend.
+
+
+/**
+ * A cache of the Long representations of small integer values.
+ * @type {Object}
+ * @api private
+ */
+Long.INT_CACHE_ = {};
+
+// NOTE: the compiler should inline these constant values below and then remove
+// these variables, so there should be no runtime penalty for these.
+
+/**
+ * Number used repeated below in calculations. This must appear before the
+ * first call to any from* function below.
+ * @type {number}
+ * @api private
+ */
+Long.TWO_PWR_16_DBL_ = 1 << 16;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Long.TWO_PWR_24_DBL_ = 1 << 24;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Long.TWO_PWR_32_DBL_ = Long.TWO_PWR_16_DBL_ * Long.TWO_PWR_16_DBL_;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Long.TWO_PWR_31_DBL_ = Long.TWO_PWR_32_DBL_ / 2;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Long.TWO_PWR_48_DBL_ = Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_16_DBL_;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Long.TWO_PWR_64_DBL_ = Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_32_DBL_;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Long.TWO_PWR_63_DBL_ = Long.TWO_PWR_64_DBL_ / 2;
+
+/** @type {Long} */
+Long.ZERO = Long.fromInt(0);
+
+/** @type {Long} */
+Long.ONE = Long.fromInt(1);
+
+/** @type {Long} */
+Long.NEG_ONE = Long.fromInt(-1);
+
+/** @type {Long} */
+Long.MAX_VALUE =
+ Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0);
+
+/** @type {Long} */
+Long.MIN_VALUE = Long.fromBits(0, 0x80000000 | 0);
+
+/**
+ * @type {Long}
+ * @api private
+ */
+Long.TWO_PWR_24_ = Long.fromInt(1 << 24);
+
+/**
+ * Expose.
+ */
+exports.Long = Long;
+},
+
+
+
+'max_key': function(module, exports, global, require, undefined){
+ /**
+ * A class representation of the BSON MaxKey type.
+ *
+ * @class Represents the BSON MaxKey type.
+ * @return {MaxKey}
+ */
+function MaxKey() {
+ if(!(this instanceof MaxKey)) return new MaxKey();
+
+ this._bsontype = 'MaxKey';
+}
+
+exports.MaxKey = MaxKey;
+},
+
+
+
+'min_key': function(module, exports, global, require, undefined){
+ /**
+ * A class representation of the BSON MinKey type.
+ *
+ * @class Represents the BSON MinKey type.
+ * @return {MinKey}
+ */
+function MinKey() {
+ if(!(this instanceof MinKey)) return new MinKey();
+
+ this._bsontype = 'MinKey';
+}
+
+exports.MinKey = MinKey;
+},
+
+
+
+'objectid': function(module, exports, global, require, undefined){
+ /**
+ * Module dependencies.
+ */
+var BinaryParser = require('./binary_parser').BinaryParser;
+
+/**
+ * Machine id.
+ *
+ * Create a random 3-byte value (i.e. unique for this
+ * process). Other drivers use a md5 of the machine id here, but
+ * that would mean an asyc call to gethostname, so we don't bother.
+ */
+var MACHINE_ID = parseInt(Math.random() * 0xFFFFFF, 10);
+
+// Regular expression that checks for hex value
+var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$");
+
+/**
+* Create a new ObjectID instance
+*
+* @class Represents the BSON ObjectID type
+* @param {String|Number} id Can be a 24 byte hex string, 12 byte binary string or a Number.
+* @return {Object} instance of ObjectID.
+*/
+var ObjectID = function ObjectID(id, _hex) {
+ if(!(this instanceof ObjectID)) return new ObjectID(id, _hex);
+
+ this._bsontype = 'ObjectID';
+ var __id = null;
+
+ // Throw an error if it's not a valid setup
+ if(id != null && 'number' != typeof id && (id.length != 12 && id.length != 24))
+ throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters");
+
+ // Generate id based on the input
+ if(id == null || typeof id == 'number') {
+ // convert to 12 byte binary string
+ this.id = this.generate(id);
+ } else if(id != null && id.length === 12) {
+ // assume 12 byte string
+ this.id = id;
+ } else if(checkForHexRegExp.test(id)) {
+ return ObjectID.createFromHexString(id);
+ } else if(!checkForHexRegExp.test(id)) {
+ throw new Error("Value passed in is not a valid 24 character hex string");
+ }
+
+ if(ObjectID.cacheHexString) this.__id = this.toHexString();
+};
+
+// Allow usage of ObjectId aswell as ObjectID
+var ObjectId = ObjectID;
+
+/**
+* Return the ObjectID id as a 24 byte hex string representation
+*
+* @return {String} return the 24 byte hex string representation.
+* @api public
+*/
+ObjectID.prototype.toHexString = function() {
+ if(ObjectID.cacheHexString && this.__id) return this.__id;
+
+ var hexString = ''
+ , number
+ , value;
+
+ for (var index = 0, len = this.id.length; index < len; index++) {
+ value = BinaryParser.toByte(this.id[index]);
+ number = value <= 15
+ ? '0' + value.toString(16)
+ : value.toString(16);
+ hexString = hexString + number;
+ }
+
+ if(ObjectID.cacheHexString) this.__id = hexString;
+ return hexString;
+};
+
+/**
+* Update the ObjectID index used in generating new ObjectID's on the driver
+*
+* @return {Number} returns next index value.
+* @api private
+*/
+ObjectID.prototype.get_inc = function() {
+ return ObjectID.index = (ObjectID.index + 1) % 0xFFFFFF;
+};
+
+/**
+* Update the ObjectID index used in generating new ObjectID's on the driver
+*
+* @return {Number} returns next index value.
+* @api private
+*/
+ObjectID.prototype.getInc = function() {
+ return this.get_inc();
+};
+
+/**
+* Generate a 12 byte id string used in ObjectID's
+*
+* @param {Number} [time] optional parameter allowing to pass in a second based timestamp.
+* @return {String} return the 12 byte id binary string.
+* @api private
+*/
+ObjectID.prototype.generate = function(time) {
+ if ('number' == typeof time) {
+ var time4Bytes = BinaryParser.encodeInt(time, 32, true, true);
+ /* for time-based ObjectID the bytes following the time will be zeroed */
+ var machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false);
+ var pid2Bytes = BinaryParser.fromShort(typeof process === 'undefined' ? Math.floor(Math.random() * 100000) : process.pid);
+ var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true);
+ } else {
+ var unixTime = parseInt(Date.now()/1000,10);
+ var time4Bytes = BinaryParser.encodeInt(unixTime, 32, true, true);
+ var machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false);
+ var pid2Bytes = BinaryParser.fromShort(typeof process === 'undefined' ? Math.floor(Math.random() * 100000) : process.pid);
+ var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true);
+ }
+
+ return time4Bytes + machine3Bytes + pid2Bytes + index3Bytes;
+};
+
+/**
+* Converts the id into a 24 byte hex string for printing
+*
+* @return {String} return the 24 byte hex string representation.
+* @api private
+*/
+ObjectID.prototype.toString = function() {
+ return this.toHexString();
+};
+
+/**
+* Converts to a string representation of this Id.
+*
+* @return {String} return the 24 byte hex string representation.
+* @api private
+*/
+ObjectID.prototype.inspect = ObjectID.prototype.toString;
+
+/**
+* Converts to its JSON representation.
+*
+* @return {String} return the 24 byte hex string representation.
+* @api private
+*/
+ObjectID.prototype.toJSON = function() {
+ return this.toHexString();
+};
+
+/**
+* Compares the equality of this ObjectID with `otherID`.
+*
+* @param {Object} otherID ObjectID instance to compare against.
+* @return {Bool} the result of comparing two ObjectID's
+* @api public
+*/
+ObjectID.prototype.equals = function equals (otherID) {
+ var id = (otherID instanceof ObjectID || otherID.toHexString)
+ ? otherID.id
+ : ObjectID.createFromHexString(otherID).id;
+
+ return this.id === id;
+}
+
+/**
+* Returns the generation time in seconds that this ID was generated.
+*
+* @return {Number} return number of seconds in the timestamp part of the 12 byte id.
+* @api public
+*/
+ObjectID.prototype.getTimestamp = function() {
+ var timestamp = new Date();
+ timestamp.setTime(Math.floor(BinaryParser.decodeInt(this.id.substring(0,4), 32, true, true)) * 1000);
+ return timestamp;
+}
+
+/**
+* @ignore
+* @api private
+*/
+ObjectID.index = 0;
+
+ObjectID.createPk = function createPk () {
+ return new ObjectID();
+};
+
+/**
+* Creates an ObjectID from a second based number, with the rest of the ObjectID zeroed out. Used for comparisons or sorting the ObjectID.
+*
+* @param {Number} time an integer number representing a number of seconds.
+* @return {ObjectID} return the created ObjectID
+* @api public
+*/
+ObjectID.createFromTime = function createFromTime (time) {
+ var id = BinaryParser.encodeInt(time, 32, true, true) +
+ BinaryParser.encodeInt(0, 64, true, true);
+ return new ObjectID(id);
+};
+
+/**
+* Creates an ObjectID from a hex string representation of an ObjectID.
+*
+* @param {String} hexString create a ObjectID from a passed in 24 byte hexstring.
+* @return {ObjectID} return the created ObjectID
+* @api public
+*/
+ObjectID.createFromHexString = function createFromHexString (hexString) {
+ // Throw an error if it's not a valid setup
+ if(typeof hexString === 'undefined' || hexString != null && hexString.length != 24)
+ throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters");
+
+ var len = hexString.length;
+
+ if(len > 12*2) {
+ throw new Error('Id cannot be longer than 12 bytes');
+ }
+
+ var result = ''
+ , string
+ , number;
+
+ for (var index = 0; index < len; index += 2) {
+ string = hexString.substr(index, 2);
+ number = parseInt(string, 16);
+ result += BinaryParser.fromByte(number);
+ }
+
+ return new ObjectID(result, hexString);
+};
+
+/**
+* @ignore
+*/
+Object.defineProperty(ObjectID.prototype, "generationTime", {
+ enumerable: true
+ , get: function () {
+ return Math.floor(BinaryParser.decodeInt(this.id.substring(0,4), 32, true, true));
+ }
+ , set: function (value) {
+ var value = BinaryParser.encodeInt(value, 32, true, true);
+ this.id = value + this.id.substr(4);
+ // delete this.__id;
+ this.toHexString();
+ }
+});
+
+/**
+ * Expose.
+ */
+exports.ObjectID = ObjectID;
+exports.ObjectId = ObjectID;
+},
+
+
+
+'symbol': function(module, exports, global, require, undefined){
+ /**
+ * A class representation of the BSON Symbol type.
+ *
+ * @class Represents the BSON Symbol type.
+ * @param {String} value the string representing the symbol.
+ * @return {Symbol}
+ */
+function Symbol(value) {
+ if(!(this instanceof Symbol)) return new Symbol(value);
+ this._bsontype = 'Symbol';
+ this.value = value;
+}
+
+/**
+ * Access the wrapped string value.
+ *
+ * @return {String} returns the wrapped string.
+ * @api public
+ */
+Symbol.prototype.valueOf = function() {
+ return this.value;
+};
+
+/**
+ * @ignore
+ * @api private
+ */
+Symbol.prototype.toString = function() {
+ return this.value;
+}
+
+/**
+ * @ignore
+ * @api private
+ */
+Symbol.prototype.inspect = function() {
+ return this.value;
+}
+
+/**
+ * @ignore
+ * @api private
+ */
+Symbol.prototype.toJSON = function() {
+ return this.value;
+}
+
+exports.Symbol = Symbol;
+},
+
+
+
+'timestamp': function(module, exports, global, require, undefined){
+ // Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Copyright 2009 Google Inc. All Rights Reserved
+
+/**
+ * Defines a Timestamp class for representing a 64-bit two's-complement
+ * integer value, which faithfully simulates the behavior of a Java "Timestamp". This
+ * implementation is derived from TimestampLib in GWT.
+ *
+ * Constructs a 64-bit two's-complement integer, given its low and high 32-bit
+ * values as *signed* integers. See the from* functions below for more
+ * convenient ways of constructing Timestamps.
+ *
+ * The internal representation of a Timestamp is the two given signed, 32-bit values.
+ * We use 32-bit pieces because these are the size of integers on which
+ * Javascript performs bit-operations. For operations like addition and
+ * multiplication, we split each number into 16-bit pieces, which can easily be
+ * multiplied within Javascript's floating-point representation without overflow
+ * or change in sign.
+ *
+ * In the algorithms below, we frequently reduce the negative case to the
+ * positive case by negating the input(s) and then post-processing the result.
+ * Note that we must ALWAYS check specially whether those values are MIN_VALUE
+ * (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as
+ * a positive number, it overflows back into a negative). Not handling this
+ * case would often result in infinite recursion.
+ *
+ * @class Represents the BSON Timestamp type.
+ * @param {Number} low the low (signed) 32 bits of the Timestamp.
+ * @param {Number} high the high (signed) 32 bits of the Timestamp.
+ */
+function Timestamp(low, high) {
+ if(!(this instanceof Timestamp)) return new Timestamp(low, high);
+ this._bsontype = 'Timestamp';
+ /**
+ * @type {number}
+ * @api private
+ */
+ this.low_ = low | 0; // force into 32 signed bits.
+
+ /**
+ * @type {number}
+ * @api private
+ */
+ this.high_ = high | 0; // force into 32 signed bits.
+};
+
+/**
+ * Return the int value.
+ *
+ * @return {Number} the value, assuming it is a 32-bit integer.
+ * @api public
+ */
+Timestamp.prototype.toInt = function() {
+ return this.low_;
+};
+
+/**
+ * Return the Number value.
+ *
+ * @return {Number} the closest floating-point representation to this value.
+ * @api public
+ */
+Timestamp.prototype.toNumber = function() {
+ return this.high_ * Timestamp.TWO_PWR_32_DBL_ +
+ this.getLowBitsUnsigned();
+};
+
+/**
+ * Return the JSON value.
+ *
+ * @return {String} the JSON representation.
+ * @api public
+ */
+Timestamp.prototype.toJSON = function() {
+ return this.toString();
+}
+
+/**
+ * Return the String value.
+ *
+ * @param {Number} [opt_radix] the radix in which the text should be written.
+ * @return {String} the textual representation of this value.
+ * @api public
+ */
+Timestamp.prototype.toString = function(opt_radix) {
+ var radix = opt_radix || 10;
+ if (radix < 2 || 36 < radix) {
+ throw Error('radix out of range: ' + radix);
+ }
+
+ if (this.isZero()) {
+ return '0';
+ }
+
+ if (this.isNegative()) {
+ if (this.equals(Timestamp.MIN_VALUE)) {
+ // We need to change the Timestamp value before it can be negated, so we remove
+ // the bottom-most digit in this base and then recurse to do the rest.
+ var radixTimestamp = Timestamp.fromNumber(radix);
+ var div = this.div(radixTimestamp);
+ var rem = div.multiply(radixTimestamp).subtract(this);
+ return div.toString(radix) + rem.toInt().toString(radix);
+ } else {
+ return '-' + this.negate().toString(radix);
+ }
+ }
+
+ // Do several (6) digits each time through the loop, so as to
+ // minimize the calls to the very expensive emulated div.
+ var radixToPower = Timestamp.fromNumber(Math.pow(radix, 6));
+
+ var rem = this;
+ var result = '';
+ while (true) {
+ var remDiv = rem.div(radixToPower);
+ var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt();
+ var digits = intval.toString(radix);
+
+ rem = remDiv;
+ if (rem.isZero()) {
+ return digits + result;
+ } else {
+ while (digits.length < 6) {
+ digits = '0' + digits;
+ }
+ result = '' + digits + result;
+ }
+ }
+};
+
+/**
+ * Return the high 32-bits value.
+ *
+ * @return {Number} the high 32-bits as a signed value.
+ * @api public
+ */
+Timestamp.prototype.getHighBits = function() {
+ return this.high_;
+};
+
+/**
+ * Return the low 32-bits value.
+ *
+ * @return {Number} the low 32-bits as a signed value.
+ * @api public
+ */
+Timestamp.prototype.getLowBits = function() {
+ return this.low_;
+};
+
+/**
+ * Return the low unsigned 32-bits value.
+ *
+ * @return {Number} the low 32-bits as an unsigned value.
+ * @api public
+ */
+Timestamp.prototype.getLowBitsUnsigned = function() {
+ return (this.low_ >= 0) ?
+ this.low_ : Timestamp.TWO_PWR_32_DBL_ + this.low_;
+};
+
+/**
+ * Returns the number of bits needed to represent the absolute value of this Timestamp.
+ *
+ * @return {Number} Returns the number of bits needed to represent the absolute value of this Timestamp.
+ * @api public
+ */
+Timestamp.prototype.getNumBitsAbs = function() {
+ if (this.isNegative()) {
+ if (this.equals(Timestamp.MIN_VALUE)) {
+ return 64;
+ } else {
+ return this.negate().getNumBitsAbs();
+ }
+ } else {
+ var val = this.high_ != 0 ? this.high_ : this.low_;
+ for (var bit = 31; bit > 0; bit--) {
+ if ((val & (1 << bit)) != 0) {
+ break;
+ }
+ }
+ return this.high_ != 0 ? bit + 33 : bit + 1;
+ }
+};
+
+/**
+ * Return whether this value is zero.
+ *
+ * @return {Boolean} whether this value is zero.
+ * @api public
+ */
+Timestamp.prototype.isZero = function() {
+ return this.high_ == 0 && this.low_ == 0;
+};
+
+/**
+ * Return whether this value is negative.
+ *
+ * @return {Boolean} whether this value is negative.
+ * @api public
+ */
+Timestamp.prototype.isNegative = function() {
+ return this.high_ < 0;
+};
+
+/**
+ * Return whether this value is odd.
+ *
+ * @return {Boolean} whether this value is odd.
+ * @api public
+ */
+Timestamp.prototype.isOdd = function() {
+ return (this.low_ & 1) == 1;
+};
+
+/**
+ * Return whether this Timestamp equals the other
+ *
+ * @param {Timestamp} other Timestamp to compare against.
+ * @return {Boolean} whether this Timestamp equals the other
+ * @api public
+ */
+Timestamp.prototype.equals = function(other) {
+ return (this.high_ == other.high_) && (this.low_ == other.low_);
+};
+
+/**
+ * Return whether this Timestamp does not equal the other.
+ *
+ * @param {Timestamp} other Timestamp to compare against.
+ * @return {Boolean} whether this Timestamp does not equal the other.
+ * @api public
+ */
+Timestamp.prototype.notEquals = function(other) {
+ return (this.high_ != other.high_) || (this.low_ != other.low_);
+};
+
+/**
+ * Return whether this Timestamp is less than the other.
+ *
+ * @param {Timestamp} other Timestamp to compare against.
+ * @return {Boolean} whether this Timestamp is less than the other.
+ * @api public
+ */
+Timestamp.prototype.lessThan = function(other) {
+ return this.compare(other) < 0;
+};
+
+/**
+ * Return whether this Timestamp is less than or equal to the other.
+ *
+ * @param {Timestamp} other Timestamp to compare against.
+ * @return {Boolean} whether this Timestamp is less than or equal to the other.
+ * @api public
+ */
+Timestamp.prototype.lessThanOrEqual = function(other) {
+ return this.compare(other) <= 0;
+};
+
+/**
+ * Return whether this Timestamp is greater than the other.
+ *
+ * @param {Timestamp} other Timestamp to compare against.
+ * @return {Boolean} whether this Timestamp is greater than the other.
+ * @api public
+ */
+Timestamp.prototype.greaterThan = function(other) {
+ return this.compare(other) > 0;
+};
+
+/**
+ * Return whether this Timestamp is greater than or equal to the other.
+ *
+ * @param {Timestamp} other Timestamp to compare against.
+ * @return {Boolean} whether this Timestamp is greater than or equal to the other.
+ * @api public
+ */
+Timestamp.prototype.greaterThanOrEqual = function(other) {
+ return this.compare(other) >= 0;
+};
+
+/**
+ * Compares this Timestamp with the given one.
+ *
+ * @param {Timestamp} other Timestamp to compare against.
+ * @return {Boolean} 0 if they are the same, 1 if the this is greater, and -1 if the given one is greater.
+ * @api public
+ */
+Timestamp.prototype.compare = function(other) {
+ if (this.equals(other)) {
+ return 0;
+ }
+
+ var thisNeg = this.isNegative();
+ var otherNeg = other.isNegative();
+ if (thisNeg && !otherNeg) {
+ return -1;
+ }
+ if (!thisNeg && otherNeg) {
+ return 1;
+ }
+
+ // at this point, the signs are the same, so subtraction will not overflow
+ if (this.subtract(other).isNegative()) {
+ return -1;
+ } else {
+ return 1;
+ }
+};
+
+/**
+ * The negation of this value.
+ *
+ * @return {Timestamp} the negation of this value.
+ * @api public
+ */
+Timestamp.prototype.negate = function() {
+ if (this.equals(Timestamp.MIN_VALUE)) {
+ return Timestamp.MIN_VALUE;
+ } else {
+ return this.not().add(Timestamp.ONE);
+ }
+};
+
+/**
+ * Returns the sum of this and the given Timestamp.
+ *
+ * @param {Timestamp} other Timestamp to add to this one.
+ * @return {Timestamp} the sum of this and the given Timestamp.
+ * @api public
+ */
+Timestamp.prototype.add = function(other) {
+ // Divide each number into 4 chunks of 16 bits, and then sum the chunks.
+
+ var a48 = this.high_ >>> 16;
+ var a32 = this.high_ & 0xFFFF;
+ var a16 = this.low_ >>> 16;
+ var a00 = this.low_ & 0xFFFF;
+
+ var b48 = other.high_ >>> 16;
+ var b32 = other.high_ & 0xFFFF;
+ var b16 = other.low_ >>> 16;
+ var b00 = other.low_ & 0xFFFF;
+
+ var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+ c00 += a00 + b00;
+ c16 += c00 >>> 16;
+ c00 &= 0xFFFF;
+ c16 += a16 + b16;
+ c32 += c16 >>> 16;
+ c16 &= 0xFFFF;
+ c32 += a32 + b32;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c48 += a48 + b48;
+ c48 &= 0xFFFF;
+ return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
+};
+
+/**
+ * Returns the difference of this and the given Timestamp.
+ *
+ * @param {Timestamp} other Timestamp to subtract from this.
+ * @return {Timestamp} the difference of this and the given Timestamp.
+ * @api public
+ */
+Timestamp.prototype.subtract = function(other) {
+ return this.add(other.negate());
+};
+
+/**
+ * Returns the product of this and the given Timestamp.
+ *
+ * @param {Timestamp} other Timestamp to multiply with this.
+ * @return {Timestamp} the product of this and the other.
+ * @api public
+ */
+Timestamp.prototype.multiply = function(other) {
+ if (this.isZero()) {
+ return Timestamp.ZERO;
+ } else if (other.isZero()) {
+ return Timestamp.ZERO;
+ }
+
+ if (this.equals(Timestamp.MIN_VALUE)) {
+ return other.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO;
+ } else if (other.equals(Timestamp.MIN_VALUE)) {
+ return this.isOdd() ? Timestamp.MIN_VALUE : Timestamp.ZERO;
+ }
+
+ if (this.isNegative()) {
+ if (other.isNegative()) {
+ return this.negate().multiply(other.negate());
+ } else {
+ return this.negate().multiply(other).negate();
+ }
+ } else if (other.isNegative()) {
+ return this.multiply(other.negate()).negate();
+ }
+
+ // If both Timestamps are small, use float multiplication
+ if (this.lessThan(Timestamp.TWO_PWR_24_) &&
+ other.lessThan(Timestamp.TWO_PWR_24_)) {
+ return Timestamp.fromNumber(this.toNumber() * other.toNumber());
+ }
+
+ // Divide each Timestamp into 4 chunks of 16 bits, and then add up 4x4 products.
+ // We can skip products that would overflow.
+
+ var a48 = this.high_ >>> 16;
+ var a32 = this.high_ & 0xFFFF;
+ var a16 = this.low_ >>> 16;
+ var a00 = this.low_ & 0xFFFF;
+
+ var b48 = other.high_ >>> 16;
+ var b32 = other.high_ & 0xFFFF;
+ var b16 = other.low_ >>> 16;
+ var b00 = other.low_ & 0xFFFF;
+
+ var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
+ c00 += a00 * b00;
+ c16 += c00 >>> 16;
+ c00 &= 0xFFFF;
+ c16 += a16 * b00;
+ c32 += c16 >>> 16;
+ c16 &= 0xFFFF;
+ c16 += a00 * b16;
+ c32 += c16 >>> 16;
+ c16 &= 0xFFFF;
+ c32 += a32 * b00;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c32 += a16 * b16;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c32 += a00 * b32;
+ c48 += c32 >>> 16;
+ c32 &= 0xFFFF;
+ c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
+ c48 &= 0xFFFF;
+ return Timestamp.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
+};
+
+/**
+ * Returns this Timestamp divided by the given one.
+ *
+ * @param {Timestamp} other Timestamp by which to divide.
+ * @return {Timestamp} this Timestamp divided by the given one.
+ * @api public
+ */
+Timestamp.prototype.div = function(other) {
+ if (other.isZero()) {
+ throw Error('division by zero');
+ } else if (this.isZero()) {
+ return Timestamp.ZERO;
+ }
+
+ if (this.equals(Timestamp.MIN_VALUE)) {
+ if (other.equals(Timestamp.ONE) ||
+ other.equals(Timestamp.NEG_ONE)) {
+ return Timestamp.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE
+ } else if (other.equals(Timestamp.MIN_VALUE)) {
+ return Timestamp.ONE;
+ } else {
+ // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
+ var halfThis = this.shiftRight(1);
+ var approx = halfThis.div(other).shiftLeft(1);
+ if (approx.equals(Timestamp.ZERO)) {
+ return other.isNegative() ? Timestamp.ONE : Timestamp.NEG_ONE;
+ } else {
+ var rem = this.subtract(other.multiply(approx));
+ var result = approx.add(rem.div(other));
+ return result;
+ }
+ }
+ } else if (other.equals(Timestamp.MIN_VALUE)) {
+ return Timestamp.ZERO;
+ }
+
+ if (this.isNegative()) {
+ if (other.isNegative()) {
+ return this.negate().div(other.negate());
+ } else {
+ return this.negate().div(other).negate();
+ }
+ } else if (other.isNegative()) {
+ return this.div(other.negate()).negate();
+ }
+
+ // Repeat the following until the remainder is less than other: find a
+ // floating-point that approximates remainder / other *from below*, add this
+ // into the result, and subtract it from the remainder. It is critical that
+ // the approximate value is less than or equal to the real value so that the
+ // remainder never becomes negative.
+ var res = Timestamp.ZERO;
+ var rem = this;
+ while (rem.greaterThanOrEqual(other)) {
+ // Approximate the result of division. This may be a little greater or
+ // smaller than the actual value.
+ var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));
+
+ // We will tweak the approximate result by changing it in the 48-th digit or
+ // the smallest non-fractional digit, whichever is larger.
+ var log2 = Math.ceil(Math.log(approx) / Math.LN2);
+ var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);
+
+ // Decrease the approximation until it is smaller than the remainder. Note
+ // that if it is too large, the product overflows and is negative.
+ var approxRes = Timestamp.fromNumber(approx);
+ var approxRem = approxRes.multiply(other);
+ while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
+ approx -= delta;
+ approxRes = Timestamp.fromNumber(approx);
+ approxRem = approxRes.multiply(other);
+ }
+
+ // We know the answer can't be zero... and actually, zero would cause
+ // infinite recursion since we would make no progress.
+ if (approxRes.isZero()) {
+ approxRes = Timestamp.ONE;
+ }
+
+ res = res.add(approxRes);
+ rem = rem.subtract(approxRem);
+ }
+ return res;
+};
+
+/**
+ * Returns this Timestamp modulo the given one.
+ *
+ * @param {Timestamp} other Timestamp by which to mod.
+ * @return {Timestamp} this Timestamp modulo the given one.
+ * @api public
+ */
+Timestamp.prototype.modulo = function(other) {
+ return this.subtract(this.div(other).multiply(other));
+};
+
+/**
+ * The bitwise-NOT of this value.
+ *
+ * @return {Timestamp} the bitwise-NOT of this value.
+ * @api public
+ */
+Timestamp.prototype.not = function() {
+ return Timestamp.fromBits(~this.low_, ~this.high_);
+};
+
+/**
+ * Returns the bitwise-AND of this Timestamp and the given one.
+ *
+ * @param {Timestamp} other the Timestamp with which to AND.
+ * @return {Timestamp} the bitwise-AND of this and the other.
+ * @api public
+ */
+Timestamp.prototype.and = function(other) {
+ return Timestamp.fromBits(this.low_ & other.low_, this.high_ & other.high_);
+};
+
+/**
+ * Returns the bitwise-OR of this Timestamp and the given one.
+ *
+ * @param {Timestamp} other the Timestamp with which to OR.
+ * @return {Timestamp} the bitwise-OR of this and the other.
+ * @api public
+ */
+Timestamp.prototype.or = function(other) {
+ return Timestamp.fromBits(this.low_ | other.low_, this.high_ | other.high_);
+};
+
+/**
+ * Returns the bitwise-XOR of this Timestamp and the given one.
+ *
+ * @param {Timestamp} other the Timestamp with which to XOR.
+ * @return {Timestamp} the bitwise-XOR of this and the other.
+ * @api public
+ */
+Timestamp.prototype.xor = function(other) {
+ return Timestamp.fromBits(this.low_ ^ other.low_, this.high_ ^ other.high_);
+};
+
+/**
+ * Returns this Timestamp with bits shifted to the left by the given amount.
+ *
+ * @param {Number} numBits the number of bits by which to shift.
+ * @return {Timestamp} this shifted to the left by the given amount.
+ * @api public
+ */
+Timestamp.prototype.shiftLeft = function(numBits) {
+ numBits &= 63;
+ if (numBits == 0) {
+ return this;
+ } else {
+ var low = this.low_;
+ if (numBits < 32) {
+ var high = this.high_;
+ return Timestamp.fromBits(
+ low << numBits,
+ (high << numBits) | (low >>> (32 - numBits)));
+ } else {
+ return Timestamp.fromBits(0, low << (numBits - 32));
+ }
+ }
+};
+
+/**
+ * Returns this Timestamp with bits shifted to the right by the given amount.
+ *
+ * @param {Number} numBits the number of bits by which to shift.
+ * @return {Timestamp} this shifted to the right by the given amount.
+ * @api public
+ */
+Timestamp.prototype.shiftRight = function(numBits) {
+ numBits &= 63;
+ if (numBits == 0) {
+ return this;
+ } else {
+ var high = this.high_;
+ if (numBits < 32) {
+ var low = this.low_;
+ return Timestamp.fromBits(
+ (low >>> numBits) | (high << (32 - numBits)),
+ high >> numBits);
+ } else {
+ return Timestamp.fromBits(
+ high >> (numBits - 32),
+ high >= 0 ? 0 : -1);
+ }
+ }
+};
+
+/**
+ * Returns this Timestamp with bits shifted to the right by the given amount, with the new top bits matching the current sign bit.
+ *
+ * @param {Number} numBits the number of bits by which to shift.
+ * @return {Timestamp} this shifted to the right by the given amount, with zeros placed into the new leading bits.
+ * @api public
+ */
+Timestamp.prototype.shiftRightUnsigned = function(numBits) {
+ numBits &= 63;
+ if (numBits == 0) {
+ return this;
+ } else {
+ var high = this.high_;
+ if (numBits < 32) {
+ var low = this.low_;
+ return Timestamp.fromBits(
+ (low >>> numBits) | (high << (32 - numBits)),
+ high >>> numBits);
+ } else if (numBits == 32) {
+ return Timestamp.fromBits(high, 0);
+ } else {
+ return Timestamp.fromBits(high >>> (numBits - 32), 0);
+ }
+ }
+};
+
+/**
+ * Returns a Timestamp representing the given (32-bit) integer value.
+ *
+ * @param {Number} value the 32-bit integer in question.
+ * @return {Timestamp} the corresponding Timestamp value.
+ * @api public
+ */
+Timestamp.fromInt = function(value) {
+ if (-128 <= value && value < 128) {
+ var cachedObj = Timestamp.INT_CACHE_[value];
+ if (cachedObj) {
+ return cachedObj;
+ }
+ }
+
+ var obj = new Timestamp(value | 0, value < 0 ? -1 : 0);
+ if (-128 <= value && value < 128) {
+ Timestamp.INT_CACHE_[value] = obj;
+ }
+ return obj;
+};
+
+/**
+ * Returns a Timestamp representing the given value, provided that it is a finite number. Otherwise, zero is returned.
+ *
+ * @param {Number} value the number in question.
+ * @return {Timestamp} the corresponding Timestamp value.
+ * @api public
+ */
+Timestamp.fromNumber = function(value) {
+ if (isNaN(value) || !isFinite(value)) {
+ return Timestamp.ZERO;
+ } else if (value <= -Timestamp.TWO_PWR_63_DBL_) {
+ return Timestamp.MIN_VALUE;
+ } else if (value + 1 >= Timestamp.TWO_PWR_63_DBL_) {
+ return Timestamp.MAX_VALUE;
+ } else if (value < 0) {
+ return Timestamp.fromNumber(-value).negate();
+ } else {
+ return new Timestamp(
+ (value % Timestamp.TWO_PWR_32_DBL_) | 0,
+ (value / Timestamp.TWO_PWR_32_DBL_) | 0);
+ }
+};
+
+/**
+ * Returns a Timestamp representing the 64-bit integer that comes by concatenating the given high and low bits. Each is assumed to use 32 bits.
+ *
+ * @param {Number} lowBits the low 32-bits.
+ * @param {Number} highBits the high 32-bits.
+ * @return {Timestamp} the corresponding Timestamp value.
+ * @api public
+ */
+Timestamp.fromBits = function(lowBits, highBits) {
+ return new Timestamp(lowBits, highBits);
+};
+
+/**
+ * Returns a Timestamp representation of the given string, written using the given radix.
+ *
+ * @param {String} str the textual representation of the Timestamp.
+ * @param {Number} opt_radix the radix in which the text is written.
+ * @return {Timestamp} the corresponding Timestamp value.
+ * @api public
+ */
+Timestamp.fromString = function(str, opt_radix) {
+ if (str.length == 0) {
+ throw Error('number format error: empty string');
+ }
+
+ var radix = opt_radix || 10;
+ if (radix < 2 || 36 < radix) {
+ throw Error('radix out of range: ' + radix);
+ }
+
+ if (str.charAt(0) == '-') {
+ return Timestamp.fromString(str.substring(1), radix).negate();
+ } else if (str.indexOf('-') >= 0) {
+ throw Error('number format error: interior "-" character: ' + str);
+ }
+
+ // Do several (8) digits each time through the loop, so as to
+ // minimize the calls to the very expensive emulated div.
+ var radixToPower = Timestamp.fromNumber(Math.pow(radix, 8));
+
+ var result = Timestamp.ZERO;
+ for (var i = 0; i < str.length; i += 8) {
+ var size = Math.min(8, str.length - i);
+ var value = parseInt(str.substring(i, i + size), radix);
+ if (size < 8) {
+ var power = Timestamp.fromNumber(Math.pow(radix, size));
+ result = result.multiply(power).add(Timestamp.fromNumber(value));
+ } else {
+ result = result.multiply(radixToPower);
+ result = result.add(Timestamp.fromNumber(value));
+ }
+ }
+ return result;
+};
+
+// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
+// from* methods on which they depend.
+
+
+/**
+ * A cache of the Timestamp representations of small integer values.
+ * @type {Object}
+ * @api private
+ */
+Timestamp.INT_CACHE_ = {};
+
+// NOTE: the compiler should inline these constant values below and then remove
+// these variables, so there should be no runtime penalty for these.
+
+/**
+ * Number used repeated below in calculations. This must appear before the
+ * first call to any from* function below.
+ * @type {number}
+ * @api private
+ */
+Timestamp.TWO_PWR_16_DBL_ = 1 << 16;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Timestamp.TWO_PWR_24_DBL_ = 1 << 24;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Timestamp.TWO_PWR_32_DBL_ = Timestamp.TWO_PWR_16_DBL_ * Timestamp.TWO_PWR_16_DBL_;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Timestamp.TWO_PWR_31_DBL_ = Timestamp.TWO_PWR_32_DBL_ / 2;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Timestamp.TWO_PWR_48_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_16_DBL_;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Timestamp.TWO_PWR_64_DBL_ = Timestamp.TWO_PWR_32_DBL_ * Timestamp.TWO_PWR_32_DBL_;
+
+/**
+ * @type {number}
+ * @api private
+ */
+Timestamp.TWO_PWR_63_DBL_ = Timestamp.TWO_PWR_64_DBL_ / 2;
+
+/** @type {Timestamp} */
+Timestamp.ZERO = Timestamp.fromInt(0);
+
+/** @type {Timestamp} */
+Timestamp.ONE = Timestamp.fromInt(1);
+
+/** @type {Timestamp} */
+Timestamp.NEG_ONE = Timestamp.fromInt(-1);
+
+/** @type {Timestamp} */
+Timestamp.MAX_VALUE =
+ Timestamp.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0);
+
+/** @type {Timestamp} */
+Timestamp.MIN_VALUE = Timestamp.fromBits(0, 0x80000000 | 0);
+
+/**
+ * @type {Timestamp}
+ * @api private
+ */
+Timestamp.TWO_PWR_24_ = Timestamp.fromInt(1 << 24);
+
+/**
+ * Expose.
+ */
+exports.Timestamp = Timestamp;
+},
+
+ });
+
+
+if(typeof module != 'undefined' && module.exports ){
+ module.exports = bson;
+
+ if( !module.parent ){
+ bson();
+ }
+}
diff --git a/node_modules/mongodb/node_modules/bson/browser_build/package.json b/node_modules/mongodb/node_modules/bson/browser_build/package.json
new file mode 100644
index 0000000..3ebb587
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/browser_build/package.json
@@ -0,0 +1,8 @@
+{ "name" : "bson"
+, "description" : "A bson parser for node.js and the browser"
+, "main": "../lib/bson/bson"
+, "directories" : { "lib" : "../lib/bson" }
+, "engines" : { "node" : ">=0.6.0" }
+, "licenses" : [ { "type" : "Apache License, Version 2.0"
+ , "url" : "http://www.apache.org/licenses/LICENSE-2.0" } ]
+}
diff --git a/node_modules/mongodb/node_modules/bson/build/Makefile b/node_modules/mongodb/node_modules/bson/build/Makefile
new file mode 100644
index 0000000..7d9b448
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/build/Makefile
@@ -0,0 +1,355 @@
+# We borrow heavily from the kernel build setup, though we are simpler since
+# we don't have Kconfig tweaking settings on us.
+
+# The implicit make rules have it looking for RCS files, among other things.
+# We instead explicitly write all the rules we care about.
+# It's even quicker (saves ~200ms) to pass -r on the command line.
+MAKEFLAGS=-r
+
+# The source directory tree.
+srcdir := ..
+abs_srcdir := $(abspath $(srcdir))
+
+# The name of the builddir.
+builddir_name ?= .
+
+# The V=1 flag on command line makes us verbosely print command lines.
+ifdef V
+ quiet=
+else
+ quiet=quiet_
+endif
+
+# Specify BUILDTYPE=Release on the command line for a release build.
+BUILDTYPE ?= Release
+
+# Directory all our build output goes into.
+# Note that this must be two directories beneath src/ for unit tests to pass,
+# as they reach into the src/ directory for data with relative paths.
+builddir ?= $(builddir_name)/$(BUILDTYPE)
+abs_builddir := $(abspath $(builddir))
+depsdir := $(builddir)/.deps
+
+# Object output directory.
+obj := $(builddir)/obj
+abs_obj := $(abspath $(obj))
+
+# We build up a list of every single one of the targets so we can slurp in the
+# generated dependency rule Makefiles in one pass.
+all_deps :=
+
+
+
+# C++ apps need to be linked with g++.
+#
+# Note: flock is used to seralize linking. Linking is a memory-intensive
+# process so running parallel links can often lead to thrashing. To disable
+# the serialization, override LINK via an envrionment variable as follows:
+#
+# export LINK=g++
+#
+# This will allow make to invoke N linker processes as specified in -jN.
+LINK ?= ./gyp-mac-tool flock $(builddir)/linker.lock $(CXX)
+
+CC.target ?= $(CC)
+CFLAGS.target ?= $(CFLAGS)
+CXX.target ?= $(CXX)
+CXXFLAGS.target ?= $(CXXFLAGS)
+LINK.target ?= $(LINK)
+LDFLAGS.target ?= $(LDFLAGS)
+AR.target ?= $(AR)
+
+# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
+# to replicate this environment fallback in make as well.
+CC.host ?= gcc
+CFLAGS.host ?=
+CXX.host ?= g++
+CXXFLAGS.host ?=
+LINK.host ?= g++
+LDFLAGS.host ?=
+AR.host ?= ar
+
+# Define a dir function that can handle spaces.
+# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
+# "leading spaces cannot appear in the text of the first argument as written.
+# These characters can be put into the argument value by variable substitution."
+empty :=
+space := $(empty) $(empty)
+
+# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
+replace_spaces = $(subst $(space),?,$1)
+unreplace_spaces = $(subst ?,$(space),$1)
+dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
+
+# Flags to make gcc output dependency info. Note that you need to be
+# careful here to use the flags that ccache and distcc can understand.
+# We write to a dep file on the side first and then rename at the end
+# so we can't end up with a broken dep file.
+depfile = $(depsdir)/$(call replace_spaces,$@).d
+DEPFLAGS = -MMD -MF $(depfile).raw
+
+# We have to fixup the deps output in a few ways.
+# (1) the file output should mention the proper .o file.
+# ccache or distcc lose the path to the target, so we convert a rule of
+# the form:
+# foobar.o: DEP1 DEP2
+# into
+# path/to/foobar.o: DEP1 DEP2
+# (2) we want missing files not to cause us to fail to build.
+# We want to rewrite
+# foobar.o: DEP1 DEP2 \
+# DEP3
+# to
+# DEP1:
+# DEP2:
+# DEP3:
+# so if the files are missing, they're just considered phony rules.
+# We have to do some pretty insane escaping to get those backslashes
+# and dollar signs past make, the shell, and sed at the same time.
+# Doesn't work with spaces, but that's fine: .d files have spaces in
+# their names replaced with other characters.
+define fixup_dep
+# The depfile may not exist if the input file didn't have any #includes.
+touch $(depfile).raw
+# Fixup path as in (1).
+sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
+# Add extra rules as in (2).
+# We remove slashes and replace spaces with new lines;
+# remove blank lines;
+# delete the first line and append a colon to the remaining lines.
+sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
+ grep -v '^$$' |\
+ sed -e 1d -e 's|$$|:|' \
+ >> $(depfile)
+rm $(depfile).raw
+endef
+
+# Command definitions:
+# - cmd_foo is the actual command to run;
+# - quiet_cmd_foo is the brief-output summary of the command.
+
+quiet_cmd_cc = CC($(TOOLSET)) $@
+cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_cxx = CXX($(TOOLSET)) $@
+cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_objc = CXX($(TOOLSET)) $@
+cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
+
+quiet_cmd_objcxx = CXX($(TOOLSET)) $@
+cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
+
+# Commands for precompiled header files.
+quiet_cmd_pch_c = CXX($(TOOLSET)) $@
+cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
+cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+quiet_cmd_pch_m = CXX($(TOOLSET)) $@
+cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
+quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
+cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
+
+# gyp-mac-tool is written next to the root Makefile by gyp.
+# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
+# already.
+quiet_cmd_mac_tool = MACTOOL $(4) $<
+cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@"
+
+quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
+cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
+
+quiet_cmd_infoplist = INFOPLIST $@
+cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
+
+quiet_cmd_touch = TOUCH $@
+cmd_touch = touch $@
+
+quiet_cmd_copy = COPY $@
+# send stderr to /dev/null to ignore messages when linking directories.
+cmd_copy = rm -rf "$@" && cp -af "$<" "$@"
+
+quiet_cmd_alink = LIBTOOL-STATIC $@
+cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %.o,$^)
+
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
+
+# TODO(thakis): Find out and document the difference between shared_library and
+# loadable_module on mac.
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
+
+# TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass
+# -bundle -single_module here (for osmesa.so).
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
+
+
+# Define an escape_quotes function to escape single quotes.
+# This allows us to handle quotes properly as long as we always use
+# use single quotes and escape_quotes.
+escape_quotes = $(subst ','\'',$(1))
+# This comment is here just to include a ' to unconfuse syntax highlighting.
+# Define an escape_vars function to escape '$' variable syntax.
+# This allows us to read/write command lines with shell variables (e.g.
+# $LD_LIBRARY_PATH), without triggering make substitution.
+escape_vars = $(subst $$,$$$$,$(1))
+# Helper that expands to a shell command to echo a string exactly as it is in
+# make. This uses printf instead of echo because printf's behaviour with respect
+# to escape sequences is more portable than echo's across different shells
+# (e.g., dash, bash).
+exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
+
+# Helper to compare the command we're about to run against the command
+# we logged the last time we ran the command. Produces an empty
+# string (false) when the commands match.
+# Tricky point: Make has no string-equality test function.
+# The kernel uses the following, but it seems like it would have false
+# positives, where one string reordered its arguments.
+# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
+# $(filter-out $(cmd_$@), $(cmd_$(1))))
+# We instead substitute each for the empty string into the other, and
+# say they're equal if both substitutions produce the empty string.
+# .d files contain ? instead of spaces, take that into account.
+command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
+ $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
+
+# Helper that is non-empty when a prerequisite changes.
+# Normally make does this implicitly, but we force rules to always run
+# so we can check their command lines.
+# $? -- new prerequisites
+# $| -- order-only dependencies
+prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
+
+# Helper that executes all postbuilds, and deletes the output file when done
+# if any of the postbuilds failed.
+define do_postbuilds
+ @E=0;\
+ for p in $(POSTBUILDS); do\
+ eval $$p;\
+ F=$$?;\
+ if [ $$F -ne 0 ]; then\
+ E=$$F;\
+ fi;\
+ done;\
+ if [ $$E -ne 0 ]; then\
+ rm -rf "$@";\
+ exit $$E;\
+ fi
+endef
+
+# do_cmd: run a command via the above cmd_foo names, if necessary.
+# Should always run for a given target to handle command-line changes.
+# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
+# Third argument, if non-zero, makes it do POSTBUILDS processing.
+# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
+# spaces already and dirx strips the ? characters.
+define do_cmd
+$(if $(or $(command_changed),$(prereq_changed)),
+ @$(call exact_echo, $($(quiet)cmd_$(1)))
+ @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
+ $(if $(findstring flock,$(word 2,$(cmd_$1))),
+ @$(cmd_$(1))
+ @echo " $(quiet_cmd_$(1)): Finished",
+ @$(cmd_$(1))
+ )
+ @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
+ @$(if $(2),$(fixup_dep))
+ $(if $(and $(3), $(POSTBUILDS)),
+ $(call do_postbuilds)
+ )
+)
+endef
+
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
+.PHONY: all
+all:
+
+# make looks for ways to re-generate included makefiles, but in our case, we
+# don't have a direct way. Explicitly telling make that it has nothing to do
+# for them makes it go faster.
+%.d: ;
+
+# Use FORCE_DO_CMD to force a target to run. Should be coupled with
+# do_cmd.
+.PHONY: FORCE_DO_CMD
+FORCE_DO_CMD:
+
+TOOLSET := target
+# Suffix rules, putting all outputs into $(obj).
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD
+ @$(call do_cmd,objc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD
+ @$(call do_cmd,objcxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+# Try building from generated source, too.
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD
+ @$(call do_cmd,objc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD
+ @$(call do_cmd,objcxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD
+ @$(call do_cmd,objc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD
+ @$(call do_cmd,objcxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+
+ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
+ $(findstring $(join ^,$(prefix)),\
+ $(join ^,bson.target.mk)))),)
+ include bson.target.mk
+endif
+
+quiet_cmd_regen_makefile = ACTION Regenerating $@
+cmd_regen_makefile = /usr/local/Cellar/node/0.10.8/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -I/Users/gootyfer/Documents/github/moocrank/node_modules/mongodb/node_modules/bson/build/config.gypi -I/usr/local/Cellar/node/0.10.8/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/Users/gootyfer/.node-gyp/0.10.8/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/gootyfer/.node-gyp/0.10.8" "-Dmodule_root_dir=/Users/gootyfer/Documents/github/moocrank/node_modules/mongodb/node_modules/bson" binding.gyp
+Makefile: $(srcdir)/../../../../../../../.node-gyp/0.10.8/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../../../../../usr/local/Cellar/node/0.10.8/lib/node_modules/npm/node_modules/node-gyp/addon.gypi
+ $(call do_cmd,regen_makefile)
+
+# "all" is a concatenation of the "all" targets from all the included
+# sub-makefiles. This is just here to clarify.
+all:
+
+# Add in dependency-tracking rules. $(all_deps) is the list of every single
+# target in our tree. Only consider the ones with .d (dependency) info:
+d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
+ifneq ($(d_files),)
+ include $(d_files)
+endif
diff --git a/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/bson.node.d b/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/bson.node.d
new file mode 100644
index 0000000..396b6bf
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/bson.node.d
@@ -0,0 +1 @@
+cmd_Release/bson.node := ./gyp-mac-tool flock ./Release/linker.lock c++ -shared -Wl,-search_paths_first -mmacosx-version-min=10.5 -arch x86_64 -L./Release -install_name @rpath/bson.node -o Release/bson.node Release/obj.target/bson/ext/bson.o -undefined dynamic_lookup
diff --git a/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/obj.target/bson/ext/bson.o.d b/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/obj.target/bson/ext/bson.o.d
new file mode 100644
index 0000000..7456b67
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/build/Release/.deps/Release/obj.target/bson/ext/bson.o.d
@@ -0,0 +1,24 @@
+cmd_Release/obj.target/bson/ext/bson.o := c++ '-D_DARWIN_USE_64_BIT_INODE=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/Users/gootyfer/.node-gyp/0.10.8/src -I/Users/gootyfer/.node-gyp/0.10.8/deps/uv/include -I/Users/gootyfer/.node-gyp/0.10.8/deps/v8/include -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-rtti -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/bson/ext/bson.o.d.raw -c -o Release/obj.target/bson/ext/bson.o ../ext/bson.cc
+Release/obj.target/bson/ext/bson.o: ../ext/bson.cc \
+ /Users/gootyfer/.node-gyp/0.10.8/deps/v8/include/v8.h \
+ /Users/gootyfer/.node-gyp/0.10.8/deps/v8/include/v8stdint.h \
+ /Users/gootyfer/.node-gyp/0.10.8/src/node.h \
+ /Users/gootyfer/.node-gyp/0.10.8/deps/uv/include/uv.h \
+ /Users/gootyfer/.node-gyp/0.10.8/deps/uv/include/uv-private/uv-unix.h \
+ /Users/gootyfer/.node-gyp/0.10.8/deps/uv/include/uv-private/ngx-queue.h \
+ /Users/gootyfer/.node-gyp/0.10.8/deps/uv/include/uv-private/uv-darwin.h \
+ /Users/gootyfer/.node-gyp/0.10.8/src/node_object_wrap.h \
+ /Users/gootyfer/.node-gyp/0.10.8/src/node_version.h \
+ /Users/gootyfer/.node-gyp/0.10.8/src/node_buffer.h ../ext/bson.h
+../ext/bson.cc:
+/Users/gootyfer/.node-gyp/0.10.8/deps/v8/include/v8.h:
+/Users/gootyfer/.node-gyp/0.10.8/deps/v8/include/v8stdint.h:
+/Users/gootyfer/.node-gyp/0.10.8/src/node.h:
+/Users/gootyfer/.node-gyp/0.10.8/deps/uv/include/uv.h:
+/Users/gootyfer/.node-gyp/0.10.8/deps/uv/include/uv-private/uv-unix.h:
+/Users/gootyfer/.node-gyp/0.10.8/deps/uv/include/uv-private/ngx-queue.h:
+/Users/gootyfer/.node-gyp/0.10.8/deps/uv/include/uv-private/uv-darwin.h:
+/Users/gootyfer/.node-gyp/0.10.8/src/node_object_wrap.h:
+/Users/gootyfer/.node-gyp/0.10.8/src/node_version.h:
+/Users/gootyfer/.node-gyp/0.10.8/src/node_buffer.h:
+../ext/bson.h:
diff --git a/node_modules/mongodb/node_modules/bson/build/Release/bson.node b/node_modules/mongodb/node_modules/bson/build/Release/bson.node
new file mode 100755
index 0000000..9a1d56e
Binary files /dev/null and b/node_modules/mongodb/node_modules/bson/build/Release/bson.node differ
diff --git a/node_modules/mongodb/node_modules/bson/build/Release/linker.lock b/node_modules/mongodb/node_modules/bson/build/Release/linker.lock
new file mode 100644
index 0000000..e69de29
diff --git a/node_modules/mongodb/node_modules/bson/build/Release/obj.target/bson/ext/bson.o b/node_modules/mongodb/node_modules/bson/build/Release/obj.target/bson/ext/bson.o
new file mode 100644
index 0000000..5d3e344
Binary files /dev/null and b/node_modules/mongodb/node_modules/bson/build/Release/obj.target/bson/ext/bson.o differ
diff --git a/node_modules/mongodb/node_modules/bson/build/binding.Makefile b/node_modules/mongodb/node_modules/bson/build/binding.Makefile
new file mode 100644
index 0000000..90bf824
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/build/binding.Makefile
@@ -0,0 +1,6 @@
+# This file is generated by gyp; do not edit.
+
+export builddir_name ?= build/./.
+.PHONY: all
+all:
+ $(MAKE) bson
diff --git a/node_modules/mongodb/node_modules/bson/build/bson.target.mk b/node_modules/mongodb/node_modules/bson/build/bson.target.mk
new file mode 100644
index 0000000..6ff8328
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/build/bson.target.mk
@@ -0,0 +1,154 @@
+# This file is generated by gyp; do not edit.
+
+TOOLSET := target
+TARGET := bson
+DEFS_Debug := \
+ '-D_DARWIN_USE_64_BIT_INODE=1' \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DBUILDING_NODE_EXTENSION' \
+ '-DDEBUG' \
+ '-D_DEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Debug := \
+ -O0 \
+ -gdwarf-2 \
+ -mmacosx-version-min=10.5 \
+ -arch x86_64 \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
+
+# Flags passed to only C files.
+CFLAGS_C_Debug := \
+ -fno-strict-aliasing
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fno-strict-aliasing
+
+# Flags passed to only ObjC files.
+CFLAGS_OBJC_Debug :=
+
+# Flags passed to only ObjC++ files.
+CFLAGS_OBJCC_Debug :=
+
+INCS_Debug := \
+ -I/Users/gootyfer/.node-gyp/0.10.8/src \
+ -I/Users/gootyfer/.node-gyp/0.10.8/deps/uv/include \
+ -I/Users/gootyfer/.node-gyp/0.10.8/deps/v8/include
+
+DEFS_Release := \
+ '-D_DARWIN_USE_64_BIT_INODE=1' \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DBUILDING_NODE_EXTENSION'
+
+# Flags passed to all source files.
+CFLAGS_Release := \
+ -Os \
+ -gdwarf-2 \
+ -mmacosx-version-min=10.5 \
+ -arch x86_64 \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
+
+# Flags passed to only C files.
+CFLAGS_C_Release := \
+ -fno-strict-aliasing
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fno-strict-aliasing
+
+# Flags passed to only ObjC files.
+CFLAGS_OBJC_Release :=
+
+# Flags passed to only ObjC++ files.
+CFLAGS_OBJCC_Release :=
+
+INCS_Release := \
+ -I/Users/gootyfer/.node-gyp/0.10.8/src \
+ -I/Users/gootyfer/.node-gyp/0.10.8/deps/uv/include \
+ -I/Users/gootyfer/.node-gyp/0.10.8/deps/v8/include
+
+OBJS := \
+ $(obj).target/$(TARGET)/ext/bson.o
+
+# Add to the list of files we specially track dependencies for.
+all_deps += $(OBJS)
+
+# CFLAGS et al overrides must be target-local.
+# See "Target-specific Variable Values" in the GNU Make manual.
+$(OBJS): TOOLSET := $(TOOLSET)
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
+
+# Suffix rules, putting all outputs into $(obj).
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# Try building from generated source, too.
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# End of this set of suffix rules
+### Rules for final target.
+LDFLAGS_Debug := \
+ -Wl,-search_paths_first \
+ -mmacosx-version-min=10.5 \
+ -arch x86_64 \
+ -L$(builddir) \
+ -install_name @rpath/bson.node
+
+LIBTOOLFLAGS_Debug := \
+ -Wl,-search_paths_first
+
+LDFLAGS_Release := \
+ -Wl,-search_paths_first \
+ -mmacosx-version-min=10.5 \
+ -arch x86_64 \
+ -L$(builddir) \
+ -install_name @rpath/bson.node
+
+LIBTOOLFLAGS_Release := \
+ -Wl,-search_paths_first
+
+LIBS := \
+ -undefined dynamic_lookup
+
+$(builddir)/bson.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
+$(builddir)/bson.node: LIBS := $(LIBS)
+$(builddir)/bson.node: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE))
+$(builddir)/bson.node: TOOLSET := $(TOOLSET)
+$(builddir)/bson.node: $(OBJS) FORCE_DO_CMD
+ $(call do_cmd,solink_module)
+
+all_deps += $(builddir)/bson.node
+# Add target alias
+.PHONY: bson
+bson: $(builddir)/bson.node
+
+# Short alias for building this executable.
+.PHONY: bson.node
+bson.node: $(builddir)/bson.node
+
+# Add executable to "all" target.
+.PHONY: all
+all: $(builddir)/bson.node
+
diff --git a/node_modules/mongodb/node_modules/bson/build/config.gypi b/node_modules/mongodb/node_modules/bson/build/config.gypi
new file mode 100644
index 0000000..f950c42
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/build/config.gypi
@@ -0,0 +1,111 @@
+# Do not edit. File was generated by node-gyp's "configure" step
+{
+ "target_defaults": {
+ "cflags": [],
+ "default_configuration": "Release",
+ "defines": [],
+ "include_dirs": [],
+ "libraries": []
+ },
+ "variables": {
+ "clang": 1,
+ "host_arch": "x64",
+ "node_install_npm": "true",
+ "node_prefix": "/usr/local/Cellar/node/0.10.8",
+ "node_shared_cares": "false",
+ "node_shared_http_parser": "false",
+ "node_shared_libuv": "false",
+ "node_shared_openssl": "false",
+ "node_shared_v8": "false",
+ "node_shared_zlib": "false",
+ "node_tag": "",
+ "node_unsafe_optimizations": 0,
+ "node_use_dtrace": "true",
+ "node_use_etw": "false",
+ "node_use_openssl": "true",
+ "node_use_perfctr": "false",
+ "python": "/usr/bin/python",
+ "target_arch": "x64",
+ "v8_enable_gdbjit": 0,
+ "v8_no_strict_aliasing": 1,
+ "v8_use_snapshot": "true",
+ "nodedir": "/Users/gootyfer/.node-gyp/0.10.8",
+ "copy_dev_lib": "true",
+ "standalone_static_library": 1,
+ "save_dev": "",
+ "browser": "",
+ "viewer": "man",
+ "rollback": "true",
+ "usage": "",
+ "globalignorefile": "/usr/local/share/npm/etc/npmignore",
+ "init_author_url": "",
+ "shell": "/bin/bash",
+ "parseable": "",
+ "userignorefile": "/Users/gootyfer/.npmignore",
+ "cache_max": "null",
+ "init_author_email": "",
+ "sign_git_tag": "",
+ "ignore": "",
+ "long": "",
+ "registry": "https://registry.npmjs.org/",
+ "fetch_retries": "2",
+ "npat": "",
+ "message": "%s",
+ "versions": "",
+ "globalconfig": "/usr/local/share/npm/etc/npmrc",
+ "always_auth": "",
+ "cache_lock_retries": "10",
+ "fetch_retry_mintimeout": "10000",
+ "proprietary_attribs": "true",
+ "coverage": "",
+ "json": "",
+ "pre": "",
+ "description": "true",
+ "engine_strict": "",
+ "https_proxy": "",
+ "init_module": "/Users/gootyfer/.npm-init.js",
+ "userconfig": "/Users/gootyfer/.npmrc",
+ "npaturl": "http://npat.npmjs.org/",
+ "node_version": "v0.10.8",
+ "user": "501",
+ "editor": "vi",
+ "save": "",
+ "tag": "latest",
+ "global": "",
+ "optional": "true",
+ "username": "",
+ "bin_links": "true",
+ "force": "",
+ "searchopts": "",
+ "depth": "null",
+ "rebuild_bundle": "true",
+ "searchsort": "name",
+ "unicode": "true",
+ "yes": "",
+ "fetch_retry_maxtimeout": "60000",
+ "strict_ssl": "true",
+ "dev": "",
+ "fetch_retry_factor": "10",
+ "group": "20",
+ "cache_lock_stale": "60000",
+ "version": "",
+ "cache_min": "10",
+ "cache": "/Users/gootyfer/.npm",
+ "searchexclude": "",
+ "color": "true",
+ "save_optional": "",
+ "user_agent": "node/v0.10.8 darwin x64",
+ "cache_lock_wait": "10000",
+ "production": "",
+ "save_bundle": "",
+ "init_version": "0.0.0",
+ "umask": "18",
+ "git": "git",
+ "init_author_name": "",
+ "onload_script": "",
+ "tmp": "/var/folders/v1/5nckjtlj63ddnl8s01cwl8pr0000gn/T/",
+ "unsafe_perm": "true",
+ "prefix": "/usr/local/share/npm",
+ "link": ""
+ }
+}
diff --git a/node_modules/mongodb/node_modules/bson/build/gyp-mac-tool b/node_modules/mongodb/node_modules/bson/build/gyp-mac-tool
new file mode 100755
index 0000000..bf059c3
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/build/gyp-mac-tool
@@ -0,0 +1,211 @@
+#!/usr/bin/env python
+# Generated by gyp. Do not edit.
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Utility functions to perform Xcode-style build steps.
+
+These functions are executed via gyp-mac-tool when using the Makefile generator.
+"""
+
+import fcntl
+import os
+import plistlib
+import re
+import shutil
+import string
+import subprocess
+import sys
+
+
+def main(args):
+ executor = MacTool()
+ exit_code = executor.Dispatch(args)
+ if exit_code is not None:
+ sys.exit(exit_code)
+
+
+class MacTool(object):
+ """This class performs all the Mac tooling steps. The methods can either be
+ executed directly, or dispatched from an argument list."""
+
+ def Dispatch(self, args):
+ """Dispatches a string command to a method."""
+ if len(args) < 1:
+ raise Exception("Not enough arguments")
+
+ method = "Exec%s" % self._CommandifyName(args[0])
+ return getattr(self, method)(*args[1:])
+
+ def _CommandifyName(self, name_string):
+ """Transforms a tool name like copy-info-plist to CopyInfoPlist"""
+ return name_string.title().replace('-', '')
+
+ def ExecCopyBundleResource(self, source, dest):
+ """Copies a resource file to the bundle/Resources directory, performing any
+ necessary compilation on each resource."""
+ extension = os.path.splitext(source)[1].lower()
+ if os.path.isdir(source):
+ # Copy tree.
+ if os.path.exists(dest):
+ shutil.rmtree(dest)
+ shutil.copytree(source, dest)
+ elif extension == '.xib':
+ return self._CopyXIBFile(source, dest)
+ elif extension == '.strings':
+ self._CopyStringsFile(source, dest)
+ else:
+ shutil.copyfile(source, dest)
+
+ def _CopyXIBFile(self, source, dest):
+ """Compiles a XIB file with ibtool into a binary plist in the bundle."""
+ tools_dir = os.environ.get('DEVELOPER_BIN_DIR', '/usr/bin')
+ args = [os.path.join(tools_dir, 'ibtool'), '--errors', '--warnings',
+ '--notices', '--output-format', 'human-readable-text', '--compile',
+ dest, source]
+ ibtool_section_re = re.compile(r'/\*.*\*/')
+ ibtool_re = re.compile(r'.*note:.*is clipping its content')
+ ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE)
+ current_section_header = None
+ for line in ibtoolout.stdout:
+ if ibtool_section_re.match(line):
+ current_section_header = line
+ elif not ibtool_re.match(line):
+ if current_section_header:
+ sys.stdout.write(current_section_header)
+ current_section_header = None
+ sys.stdout.write(line)
+ return ibtoolout.returncode
+
+ def _CopyStringsFile(self, source, dest):
+ """Copies a .strings file using iconv to reconvert the input into UTF-16."""
+ input_code = self._DetectInputEncoding(source) or "UTF-8"
+ fp = open(dest, 'w')
+ args = ['/usr/bin/iconv', '--from-code', input_code, '--to-code',
+ 'UTF-16', source]
+ subprocess.call(args, stdout=fp)
+ fp.close()
+
+ def _DetectInputEncoding(self, file_name):
+ """Reads the first few bytes from file_name and tries to guess the text
+ encoding. Returns None as a guess if it can't detect it."""
+ fp = open(file_name, 'rb')
+ try:
+ header = fp.read(3)
+ except e:
+ fp.close()
+ return None
+ fp.close()
+ if header.startswith("\xFE\xFF"):
+ return "UTF-16BE"
+ elif header.startswith("\xFF\xFE"):
+ return "UTF-16LE"
+ elif header.startswith("\xEF\xBB\xBF"):
+ return "UTF-8"
+ else:
+ return None
+
+ def ExecCopyInfoPlist(self, source, dest):
+ """Copies the |source| Info.plist to the destination directory |dest|."""
+ # Read the source Info.plist into memory.
+ fd = open(source, 'r')
+ lines = fd.read()
+ fd.close()
+
+ # Go through all the environment variables and replace them as variables in
+ # the file.
+ for key in os.environ:
+ if key.startswith('_'):
+ continue
+ evar = '${%s}' % key
+ lines = string.replace(lines, evar, os.environ[key])
+
+ # Write out the file with variables replaced.
+ fd = open(dest, 'w')
+ fd.write(lines)
+ fd.close()
+
+ # Now write out PkgInfo file now that the Info.plist file has been
+ # "compiled".
+ self._WritePkgInfo(dest)
+
+ def _WritePkgInfo(self, info_plist):
+ """This writes the PkgInfo file from the data stored in Info.plist."""
+ plist = plistlib.readPlist(info_plist)
+ if not plist:
+ return
+
+ # Only create PkgInfo for executable types.
+ package_type = plist['CFBundlePackageType']
+ if package_type != 'APPL':
+ return
+
+ # The format of PkgInfo is eight characters, representing the bundle type
+ # and bundle signature, each four characters. If that is missing, four
+ # '?' characters are used instead.
+ signature_code = plist.get('CFBundleSignature', '????')
+ if len(signature_code) != 4: # Wrong length resets everything, too.
+ signature_code = '?' * 4
+
+ dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo')
+ fp = open(dest, 'w')
+ fp.write('%s%s' % (package_type, signature_code))
+ fp.close()
+
+ def ExecFlock(self, lockfile, *cmd_list):
+ """Emulates the most basic behavior of Linux's flock(1)."""
+ # Rely on exception handling to report errors.
+ fd = os.open(lockfile, os.O_RDONLY|os.O_NOCTTY|os.O_CREAT, 0o666)
+ fcntl.flock(fd, fcntl.LOCK_EX)
+ return subprocess.call(cmd_list)
+
+ def ExecFilterLibtool(self, *cmd_list):
+ """Calls libtool and filters out 'libtool: file: foo.o has no symbols'."""
+ libtool_re = re.compile(r'^libtool: file: .* has no symbols$')
+ libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE)
+ _, err = libtoolout.communicate()
+ for line in err.splitlines():
+ if not libtool_re.match(line):
+ print >>sys.stderr, line
+ return libtoolout.returncode
+
+ def ExecPackageFramework(self, framework, version):
+ """Takes a path to Something.framework and the Current version of that and
+ sets up all the symlinks."""
+ # Find the name of the binary based on the part before the ".framework".
+ binary = os.path.basename(framework).split('.')[0]
+
+ CURRENT = 'Current'
+ RESOURCES = 'Resources'
+ VERSIONS = 'Versions'
+
+ if not os.path.exists(os.path.join(framework, VERSIONS, version, binary)):
+ # Binary-less frameworks don't seem to contain symlinks (see e.g.
+ # chromium's out/Debug/org.chromium.Chromium.manifest/ bundle).
+ return
+
+ # Move into the framework directory to set the symlinks correctly.
+ pwd = os.getcwd()
+ os.chdir(framework)
+
+ # Set up the Current version.
+ self._Relink(version, os.path.join(VERSIONS, CURRENT))
+
+ # Set up the root symlinks.
+ self._Relink(os.path.join(VERSIONS, CURRENT, binary), binary)
+ self._Relink(os.path.join(VERSIONS, CURRENT, RESOURCES), RESOURCES)
+
+ # Back to where we were before!
+ os.chdir(pwd)
+
+ def _Relink(self, dest, link):
+ """Creates a symlink to |dest| named |link|. If |link| already exists,
+ it is overwritten."""
+ if os.path.lexists(link):
+ os.remove(link)
+ os.symlink(dest, link)
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
diff --git a/node_modules/mongodb/node_modules/bson/build_browser.js b/node_modules/mongodb/node_modules/bson/build_browser.js
new file mode 100644
index 0000000..bb80238
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/build_browser.js
@@ -0,0 +1,7 @@
+require('one');
+
+one('./package.json')
+ .tie('bson', BSON)
+ // .exclude('buffer')
+ .tie('buffer', {})
+ .save('./browser_build/bson.js')
\ No newline at end of file
diff --git a/node_modules/mongodb/node_modules/bson/builderror.log b/node_modules/mongodb/node_modules/bson/builderror.log
new file mode 100644
index 0000000..e69de29
diff --git a/node_modules/mongodb/node_modules/bson/ext/Makefile b/node_modules/mongodb/node_modules/bson/ext/Makefile
new file mode 100644
index 0000000..435999e
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/ext/Makefile
@@ -0,0 +1,28 @@
+NODE = node
+name = all
+JOBS = 1
+
+all:
+ rm -rf build .lock-wscript bson.node
+ node-waf configure build
+ cp -R ./build/Release/bson.node . || true
+
+all_debug:
+ rm -rf build .lock-wscript bson.node
+ node-waf --debug configure build
+ cp -R ./build/Release/bson.node . || true
+
+clang:
+ rm -rf build .lock-wscript bson.node
+ CXX=clang node-waf configure build
+ cp -R ./build/Release/bson.node . || true
+
+clang_debug:
+ rm -rf build .lock-wscript bson.node
+ CXX=clang node-waf --debug configure build
+ cp -R ./build/Release/bson.node . || true
+
+clean:
+ rm -rf build .lock-wscript bson.node
+
+.PHONY: all
\ No newline at end of file
diff --git a/node_modules/mongodb/node_modules/bson/ext/bson.cc b/node_modules/mongodb/node_modules/bson/ext/bson.cc
new file mode 100644
index 0000000..b910d79
--- /dev/null
+++ b/node_modules/mongodb/node_modules/bson/ext/bson.cc
@@ -0,0 +1,1006 @@
+//===========================================================================
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#endif
+
+#include
+
+// this and the above block must be around the v8.h header otherwise
+// v8 is not happy
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#ifdef __sun
+ #include
+#endif
+
+#include "bson.h"
+
+using namespace v8;
+using namespace node;
+
+//===========================================================================
+
+void DataStream::WriteObjectId(const Handle