Update mn.coffee (#6153)

Update mn.coffee (#6153)

* Update mn.coffee

Adding the translations into the mn.coffee file instead of the mon.coffee from now on. I think I need to do it all over again because the code's changed considerably since my first commit in 2015, but I'm improving on Google Translate, so should be easy to batch them by the hundreds on my weekends.

* Update mn.coffee

* Update mn.coffee

Co-authored-by: Valentin Bryukhanov <53545457af642b0f8712bb2cc004f120ce4436f4@gmail.com>

--- app/locale/mn.coco.coffee
+++ app/locale/mn.coco.coffee
@@ -1,105 +1,105 @@
 module.exports = nativeDescription: "Монгол хэл", englishDescription: "Mongolian", translation:

-#  new_home:
-#    title: "CodeCombat - Coding games to learn Python and JavaScript"
-#    meta_keywords: "CodeCombat, python, javascript, Coding Games"
-#    meta_description: "Learn typed code through a programming game. Learn Python, JavaScript, and HTML as you solve puzzles and learn to make your own coding games and websites."
-#    meta_og_url: "https://codecombat.com"
-#    become_investor: "to become an investor in CodeCombat"
-#    built_for_teachers_title: "A Coding Game Built with Teachers in Mind"
-#    built_for_teachers_blurb: "Teaching kids to code can often feel overwhelming. CodeCombat helps all educators teach students how to code in either JavaScript or Python, two of the most popular programming languages. With a comprehensive curriculum that includes six computer science units and reinforces learning through project-based game development and web development units, kids will progress on a journey from basic syntax to recursion!"
-#    built_for_teachers_subtitle1: "Computer Science"
-#    built_for_teachers_subblurb1: "Starting with our free Introduction to Computer Science course, students master core coding concepts such as while/for loops, functions, and algorithms."
-#    built_for_teachers_subtitle2: "Game Development"
-#    built_for_teachers_subblurb2: "Learners construct mazes and use basic input handling to code their own games that can be shared with friends and family."
-#    built_for_teachers_subtitle3: "Web Development"
-#    built_for_teachers_subblurb3: "Using HTML, CSS, and jQuery, learners flex their creative muscles to program their own webpages with a custom URL to share with their classmates."
-#    century_skills_title: "21st Century Skills"
-#    century_skills_blurb1: "Students Don't Just Level Up Their Hero, They Level Up Themselves"
-#    century_skills_quote1: "You mess up…so then you think about all of the possible ways to fix it, and then try again. I wouldn't be able to get here without trying hard."
-#    century_skills_subtitle1: "Critical Thinking"
-#    century_skills_subblurb1: "With coding puzzles that are naturally scaffolded into increasingly challenging levels, CodeCombat's programming game ensures kids are always practicing critical thinking."
-#    century_skills_quote2: "Everyone else was making mazes, so I thought, ‘capture the flag’ and that’s what I did."
-#    century_skills_subtitle2: "Creativity"
-#    century_skills_subblurb2: "CodeCombat encourages students to showcase their creativity by building and sharing their own games and webpages."
-#    century_skills_quote3: "If I got stuck on a level. I would work with people around me until we were all able to figure it out."
-#    century_skills_subtitle3: "Collaboration"
-#    century_skills_subblurb3: "Throughout the game, there are opportunities for students to collaborate when they get stuck and to work together using our pair programming guide."
-#    century_skills_quote4: "I’ve always had aspirations of designing video games and learning how to code ... this is giving me a great starting point."
-#    century_skills_subtitle4: "Communication"
-#    century_skills_subblurb4: "Coding requires kids to practice new forms of communication, including communicating with the computer itself and conveying their ideas using the most efficient code."
-#    classroom_in_box_title: "We Strive To:"
-#    classroom_in_box_blurb1: "Engage every student so that they believe coding is for them."
-#    classroom_in_box_blurb2: "Empower any educator to feel confident when teaching coding."
-#    classroom_in_box_blurb3: "Inspire all school leaders to create a world-class computer science program."
-#    classroom_in_box_blurb4: ""
-#    covid19_banner_blurb: "We are offering free access to our full curriculum to educators and schools affected by school closures."
-#    click_here: "Click here"
-#    creativity_rigor_title: "Where Creativity Meets Rigor"
-#    creativity_rigor_subtitle1: "Make coding fun and teach real-world skills"
-#    creativity_rigor_blurb1: "Students type real Python and JavaScript while playing games that encourage trial-and-error, critical thinking, and creativity. Students then apply the coding skills they’ve learned by developing their own games and websites in project-based courses."
-#    creativity_rigor_subtitle2: "Reach students at their level"
-#    creativity_rigor_blurb2: "Every CodeCombat level is scaffolded based on millions of data points and optimized to adapt to each learner. Practice levels and hints help students when they get stuck, and challenge levels assess students' learning throughout the game."
-#    creativity_rigor_subtitle3: "Built for all teachers, regardless of experience"
-#    creativity_rigor_blurb3: "CodeCombat’s self-paced, standards-aligned curriculum makes teaching computer science possible for everyone. CodeCombat equips teachers with the training, instructional resources, and dedicated support to feel confident and successful in the classroom."
-#    featured_partners_title1: "Featured In"
-#    featured_partners_title2: "Awards & Partners"
-#    featured_partners_blurb1: "Clever Partner"
-#    featured_partners_blurb2: "Best Creativity Tool for Students"
-#    featured_partners_blurb3: "Top Pick for Learning"
-#    featured_partners_blurb4: "Code.org Official Partner"
-#    featured_partners_blurb5: "CSforAll Official Member"
-#    featured_partners_blurb6: "Hour of Code Activity Partner"
-#    for_leaders_title: "For School Leaders"
-#    for_leaders_blurb: "A Comprehensive, Standards-Aligned Computer Science Program"
-#    for_leaders_subtitle1: "Easy Implementation"
-#    for_leaders_subblurb1: "A web-based program that requires no IT support. Get started in under 5 minutes using Google or Clever Single Sign-On (SSO)."
-#    for_leaders_subtitle2: "Full Coding Curriculum"
-#    for_leaders_subblurb2: "A standards-aligned curriculum with instructional resources and professional development to enable any teacher to teach computer science."
-#    for_leaders_subtitle3: "Flexible Use Cases"
-#    for_leaders_subblurb3: "Whether you want to build a Middle School coding elective, a CTE pathway, or are teaching an Intro to CS class, CodeCombat is tailored to suit your needs."
-#    for_leaders_subtitle4: "Real-World Skills"
-#    for_leaders_subblurb4: "Students build grit and develop a growth mindset through coding challenges that prepare them for the 500K+ open computing jobs."
-#    for_teachers_title: "For Teachers"
-#    for_teachers_blurb: "Tools to Unlock Student Potential"
-#    for_teachers_subtitle1: "Project-Based Learning"
-#    for_teachers_subblurb1: "Promote creativity, problem-solving, and confidence in project-based courses where students develop their own games and webpages."
-#    for_teachers_subtitle2: "Teacher Dashboard"
-#    for_teachers_subblurb2: "View data on student progress, discover curriculum resources, and access real-time support to empower student learning."
-#    for_teachers_subtitle3: "Built-in Assessments"
-#    for_teachers_subblurb3: "Personalize instruction and ensure students understand core concepts with formative and summative assessments."
-#    for_teachers_subtitle4: "Automatic Differentiation"
-#    for_teachers_subblurb4: "Engage all learners in a diverse classroom with practice levels that adapt to each student's learning needs."
-#    game_based_blurb: "CodeCombat is a game-based computer science program where students type real code and see their characters react in real time."
-#    get_started: "Get started"
-#    global_title: "Join Our Global Community of Learners and Educators"
-#    global_subtitle1: "Learners"
-#    global_subtitle2: "Lines of Code"
-#    global_subtitle3: "Teachers"
-#    global_subtitle4: "Countries"
-#    go_to_my_classes: "Go to my classes"
-#    go_to_my_courses: "Go to my courses"
-#    quotes_quote1: "Name any program online, I’ve tried it. None of them match up to CodeCombat. Any teacher who wants their students to learn how to code... start here!"
-#    quotes_quote2: " I was surprised about how easy and intuitive CodeCombat makes learning computer science. The scores on the AP exam were much higher than I expected and I believe CodeCombat is the reason why this was the case."
-#    quotes_quote3: "CodeCombat has been the most beneficial for teaching my students real-life coding capabilities. My husband is a software engineer and he has tested out all of my programs. He put this as his top choice."
-#    quotes_quote4: "The feedback … has been so positive that we are structuring a computer science class around CodeCombat. The program really engages the students with a gaming style platform that is entertaining and instructional at the same time. Keep up the good work, CodeCombat!"
-#    see_example: "See example"
-#    slogan: "The most engaging way to learn computer science"
-#    teach_cs1_free: "Teach CS1 Free"
-#    teachers_love_codecombat_title: "Teachers Love CodeCombat"
-#    teachers_love_codecombat_blurb1: "Report that their students enjoy using CodeCombat to learn how to code"
-#    teachers_love_codecombat_blurb2: "Would recommend CodeCombat to other computer science teachers"
-#    teachers_love_codecombat_blurb3: "Say that CodeCombat helps them support students’ problem solving abilities"
-#    teachers_love_codecombat_subblurb: "In partnership with McREL International, a leader in research-based guidance and evaluations of educational technology."
-#    top_banner_blurb: "Parents, give your child the gift of coding and personalized instruction with our live teachers!"
-#    try_the_game: "Try the game"
-#    classroom_edition: "Classroom Edition:"
-#    learn_to_code: "Learn to code:"
-#    play_now: "Play Now"
-#    im_a_parent: "I'm a Parent"
-#    im_an_educator: "I'm an Educator"
-#    im_a_teacher: "I'm a Teacher"
-#    im_a_student: "I'm a Student"
+  new_home: # шинэ_байр:
+    title:  "CodeCombat - Python болон JavaScript хэлийг сурах кодчилолын тоглоомууд"
+    meta_keywords:  "CodeCombat, python, javascript, Coding Games"
+    meta_description:  "Програмчлалын тоглоомоор код бичиж сур. Төрөл бүрийн оньсыг тайлж, өөрийн гараар кодчилох тоглоом болон вэбсайт хийнгээ Python, JavaScript, HTML-ийг сур."
+    meta_og_url:  "https://codecombat.com"
+    become_investor:  "CodeCombat-д хөрөнгө оруулагч болох"
+    built_for_teachers_title:  "Багш нартай оюун ухаанаар бүтээсэн кодчиллын тоглоом"
+    built_for_teachers_blurb:  "Хүүхдүүдэд код заахад ихэнхдээ хэцүү санагддаг. CodeCombat нь бүх сурган хүмүүжүүлэгчдэд хамгийн түгээмэл програмчлалын хоёр хэл болох JavaScript эсвэл Python програмын аль алинаар нь код бичихийг заахад тусалдаг. Компьютерийн шинжлэх ухааны зургаан нэгжийг багтаасан иж бүрэн сургалтын хөтөлбөртэй, тоглоом болон веб хөгжүүлэх төсөл дээр суурилсан сургалтын ачаар, танай хүүхдүүд үндсэн синтаксаас рекурс хүртэл боловсрох болно!"
+    built_for_teachers_subtitle1:  "Компьютерийн шинжлэх ухаан"
+    built_for_teachers_subblurb1:  "Манай Компьютерийн ухааны үнэгүй танилцуулга курсээс эхлэн сурагчид \"while\" болон \"for\" давталт, функц, алгоритм гэх мэт програмчлалын зарчмуудыг эзэмшдэг."
+    built_for_teachers_subtitle2:  "Тоглоом хөгжүүлэх"
+    built_for_teachers_subblurb2:  "Сурагчид төөрдөг байшин барьж, програмчлалын үндсэн оролтын аргыг ашиглан найз нөхөд, гэр бүлийнхэнтэйгээ хуваалцаж болох тоглоомуудаа кодлоно."
+    built_for_teachers_subtitle3:  "Вэб хөгжүүлэлт"
+    built_for_teachers_subblurb3:  "Сурагч нар бүтээлч чадвараа хөгжүүлэн HTML, CSS, jQuery ашиглаж өөрсдийн вэбсайтаа хөгжүүлж, тэр нь ангийнхантайгаа хуваалцах тусгай URL-тай болно."
+    century_skills_title:  "21-р зууны ур чадвар"
+    century_skills_blurb1:  "сурагчид зөвхөн баатараа үе ахиулаад зогсохгүй өөрсдийгөө үе ахиулах болно"
+    century_skills_quote1:  "Би алдаа гаргасан ч... Үүнийг засах бүх боломжит арга замын талаар бодож үзээд дахин оролдоно. Би тэгж их хичээхгүйгээр энэ өндөрлөгт хүрэх боломжгүй байсан."
+    century_skills_subtitle1:  "Шүүмжлэлт сэтгэлгээ"
+    century_skills_subblurb1:  "Программын бодлогуудыг илүү төвөгтэй түвшин рүү хүрэх бүтэцтэй учир CodeCombat тоглоом нь хүүхдүүдийн шүүмжлэлт сэтгэлгээг үргэлж дадлагажуулдаг."
+    century_skills_quote2:  "Бусад хүмүүс төөрдөг байшин хийж байсан болохоор би \"туг булаацалдъя\"гэж бодсон, тэгээд үүнийг хийсэн."
+    century_skills_subtitle2:  "Бүтээлч байдал"
+    century_skills_subblurb2:  "CodeCombat-ын дэмжлэгтэйгээр сурагчид тоглоом, вэб хуудас хөгжүүлж, бүтээлч сэтгэлгээгээ бусдад харуулах боломжтой."
+    century_skills_quote3:  "Хэрэв би нэг түвшинд гацчихвал, эргэн тойрныхоо хүмүүстэй бодож байгаад учрыг нь олчихдог."
+    century_skills_subtitle3:  "Хамтын ажиллагаа"
+    century_skills_subblurb3:  "Тоглоомын туршид сурагчид гацах үедээ манай хосоороо кодчлох удирдамжыг ашиглан хоёроороо хамтран ажиллах боломжтой."
+    century_skills_quote4:  "Би үргэлж видео тоглоом зохион бүтээх, код бичихийг сурах хүсэл эрмэлзэлтэй байсан ... энэ нь надад маш сайн эхлэх цэгийг өгч байна."
+    century_skills_subtitle4:  "Харилцаа холбоо"
+    century_skills_subblurb4:  "Кодчилол нь хүүхдүүдээс харилцааны шинэ хэлбэрээр дадлага хийхийг шаарддаг. Компьютертай өөрөө харьцах, тэдний санаа бодлыг хамгийн үр дүнтэй код ашиглан дамжуулах."
+    classroom_in_box_title:  "Бидний хүрэх эрмэлзэл: "
+    classroom_in_box_blurb1:  "Сурагч бүр кодчилол хийж чадна гэдэгтээ итгэтэл нь тулж ажиллах"
+    classroom_in_box_blurb2:  "Ямар ч сурган хүмүүжүүлэгчид кодчиллыг заахдаа өөртөө итгэлтэй байх чадварыг олгох."
+    classroom_in_box_blurb3:  "Бүх сургуулийн удирдагчдад дэлхийн жишигт нийцсэн компьютерийн хөтөлбөрийг бий болгох урам зориг өгөх."
+    classroom_in_box_blurb4:  ""
+    covid19_banner_blurb:  "Сургуулиуд хаагдсан энэ үеэр сурган хүмүүжүүлэгчид болон сургуулиудад бид сургалтынхаа бүрэн хөтөлбөрт үнэгүй нэвтрэх боломжийг санал болгож байна."
+    click_here:  "Энд дар"
+    creativity_rigor_title:  "Бүтээлч зан, чармайлт хоёр уулздаг газар"
+    creativity_rigor_subtitle1:  "Кодчиллыг хөгжилтэй болгож, дэлхийн ур чадварыг заах"
+    creativity_rigor_blurb1:  "Сурагчид шүүмжлэлт сэтгэлгээ, бүтээлч сэтгэлгээг хөгжүүлэх тоглоомыг алдаж онох байдлаар тоглохдоо жинхэнэ Python, JavaScript-ын код бичнэ. Дараа нь сурагчид өөрсдийн тоглоом, вэбсайтаа боловсруулж, сурсан чадвараа хэрэгжүүлдэг."
+    creativity_rigor_subtitle2:  "Сурагчдын өөр өөрсдийнх нь түвшинд ажилла"
+    creativity_rigor_blurb2:  "CodeCombat-ын түвшин бүрийг олон сая өгөгдлийн цэг дээр үндэслэн боловсруулж, сурагч бүрт оновчтой заахаар дасан зохицдог болгосон. Дадлага хийх түвшин, шпи зэрэг нь үеэ давалгүй гацсан сурагчдад тусалдаг бөгөөд сорилтын түвшин нь тоглоомын явцад сурагчидын сурсан чадварыг үнэлдэг."
+    creativity_rigor_subtitle3:  "Туршлагаас үл хамааран бүх багш нарт зориулан бүтээсэн"
+    creativity_rigor_blurb3:  "CodeCombat-ийн бие даасан, стандартад нийцсэн сургалтын хөтөлбөр нь компьютерийн шинжлэх ухааныг хүн бүрт заах боломжтой болгодог. CodeCombat нь багш нарыг анги танхимд өөртөө итгэлтэй, амжилтанд хүрэхийн тулд сургалт, сургалтын нөөц, зориулалтын дэмжлэгээр хангадаг."
+    featured_partners_title1:  "Онцолсон газрууд:"
+    featured_partners_title2:  "Шагналууд ба түншүүд"
+    featured_partners_blurb1:  "Ухаалаг түнш"
+    featured_partners_blurb2:  "Сурагчдад зориулсан шилдэг бүтээлч хэрэгсэл"
+    featured_partners_blurb3:  "Сурах шилдэг сонголт"
+    featured_partners_blurb4:  "Code.org албан ёсны түнш"
+    featured_partners_blurb5:  "CSforAll албан ёсны гишүүн"
+    featured_partners_blurb6:  "Кодын үйл ажиллагааны цаг"
+    for_leaders_title:  "Сургуулийн удирдагчдад зориулсан"
+    for_leaders_blurb:  "Компьютерийн шинжлэх ухааны стандарт, стандартад нийцсэн цогц хөтөлбөр"
+    for_leaders_subtitle1:  "Хялбар хэрэгжүүлэлт"
+    for_leaders_subblurb1:  "Ай Ти-гийн дэмжлэг шаарддаггүй вэб дээр суурилсан програм. Google эсвэл Clever Single Sign-On (SSO) ашиглан 5 минутын дотор эхлээрэй."
+    for_leaders_subtitle2:  "Бүрэн кодчиллын хөтөлбөр"
+    for_leaders_subblurb2:  "Аливаа багшид компьютерийн ухааныг заах боломжийг олгох сургалтын нөөц, мэргэжил дээшлүүлэлтийн стандартад нийцсэн сургалтын хөтөлбөр."
+    for_leaders_subtitle3:  "Уян хатан хэрэглээний боломжууд"
+    for_leaders_subblurb3:  "Дунд ангийн кодчилолын сонгон, CTE хөтөлбөр эсвэл Компьютерийн хичээлийн эхлэлийг тавихын аль нь ч байсан CodeCombat нь таны хэрэгцээнд нийцнэ."
+    for_leaders_subtitle4:  "Амьдралд хэрэглэгдэх ур чадвар"
+    for_leaders_subblurb4:  "Сурагчид 500 мянга гаран компьютерийн ажилд бэлтгэх кодчиллын бодлогуудыг бодож, цаашид дэвжих сэтгэлгээгээ хөгжүүлдэг."
+    for_teachers_title:  "Багш нарт зориулсан"
+    for_teachers_blurb:  "Оюутны чадавхийг нээх хэрэгсэл"
+    for_teachers_subtitle1:  "Төсөлд суурилсан сургалт"
+    for_teachers_subblurb1:  "Сурагчид өөрсдийн тоглоом, вэбсайтаа өөрсдөө боловсруулдаг төсөл дээр суурилсан сургалтандаар бүтээлч байдал, асуудлыг шийдвэрлэх, өөртөө итгэх итгэлийг түгээ."
+    for_teachers_subtitle2:  "Багшийн самбар"
+    for_teachers_subblurb2:  "Сурагчдын ахиц дэвшлийн талаарх өгөгдлийг харах, сургалтын хөтөлбөрийн нөөцийг олж нээх, оюутны сурах чадварыг бэхжүүлэх бодит цагийн дэмжлэг авах."
+    for_teachers_subtitle3:  "Баригдсан үнэлгээ"
+    for_teachers_subblurb3:  "Сургалтыг сурагч бүрт тааруулж, үндсэн ойлголтуудыг ойлгосон эсэхийг форматив, сумматив үнэлгээгээр шалгах."
+    for_teachers_subtitle4:  "Автомат ялгах"
+    for_teachers_subblurb4:  "Бүх сурагчдыг өөр өөрсдийн сурах хэрэгцээнд нийцүүлсэн дадлага хийх түвшинд тоглуулах олон ангид хамруул."
+    game_based_blurb:  "CodeCombat бол сурагчдад бодит кодыг бичиж, дүрүүд нь тэр даруй хариу үйлдэл үзүүлэхийг харуулдаг тоглоомонд суурилсан компьютерийн програм юм."
+    get_started:  "Эхэлцгээе"
+    global_title:  "Манай дэлхийн сурагчид ба сурган хүмүүжүүлэгчдийн нийгэмлэгт нэгдээрэй"
+    global_subtitle1:  "Сурагчид"
+    global_subtitle2:  "Кодын мөрүүд"
+    global_subtitle3:  "Багш нар"
+    global_subtitle4:  "Улс орнууд"
+    go_to_my_classes:  "Миний ангиуд руу очих"
+    go_to_my_courses:  "Миний дамжаанууд руу очих"
+    quotes_quote1:  "Аль ч онлайн програм байсан би туршиж үзсэн. Тэдний хэн нь ч CodeCombat-тай дүйцэхгүй. Сурагчдадаа код бичихийг сургахыг хүссэн ямар ч багш ... эндээс эхэл!"
+    quotes_quote2:  "CodeCombat нь компьютерийн ухаанд суралцахад ямар хялбар бөгөөд ойлгомжтой болгосныг би гайхаж байсан. AP шалгалтын оноо миний бодож байснаас хамаагүй өндөр байсан. Ийм нөхцөл байдал үүссэн шалтгаан нь CodeCombat гэж би итгэж байна."
+    quotes_quote3:  "CodeCombat нь шавь нартаа бодит кодчиллын чадварыг заахад хамгийн их ашиг тустай байсан. Нөхөр маань програм хангамжийн инженер мэргэжилтэй бөгөөд миний бүх програмыг туршиж үзсэн. Тэр үүнийг өөрийн хамгийн сайн сонголт болгосон."
+    quotes_quote4:  "Сурагчдын сэтгэгдэл маш эерэг байсан тул бид CodeCombat дээр суурилсан компьютерийн ухааны хичээлийг зохион байгуулж байна. Хөтөлбөр нь хөгжилтэй, сургамжтай тоглоомын хэв маягийн платформтой учир сурагчдыг үнэхээр татан оролцуулдаг. Үргэлжлүүлэн ажиллаарай, CodeCombat!"
+    see_example:  "Жишээ харах"
+    slogan:  "Компьютерийн ухааныг сурах хамгийн сонирхолтой арга зам"
+    teach_cs1_free:  "КУ1-ийг үнэгүй заах"
+    teachers_love_codecombat_title:  "Багш нар CodeCombat-т дуртай"
+    teachers_love_codecombat_blurb1:  "Сурагчид нь CodeCombat ашиглан код бичихэд суралцах дуртай байдаг талаар мэдээлдэг"
+    teachers_love_codecombat_blurb2:  "CodeCombat-ийг бусад компьютерийн багш нарт санал болгож байна"
+    teachers_love_codecombat_blurb3:  "CodeCombat нь сурагчдын асуудлыг шийдвэрлэх чадвараа хөгжүүлэхэд нь тусалдаг гэж хэлэв."
+    teachers_love_codecombat_subblurb:  "Боловсролын технологийн судалгаанд суурилсан удирдамж, үнэлгээний чиглэлээр тэргүүлэгч McREL International компанитай хамтран."
+    top_banner_blurb:  "Эцэг эхчүүд ээ, энэ баярын үеэр хүүхдэдээ кодчилол, хувийн зааварчилгаа бэлэглээрэй!"
+    try_the_game:  "Тоглоомыг туршиж үзээрэй"
+    classroom_edition:  "Танхимын хичээлийн хувилбар:"
+    learn_to_code:  "Код бичиж сур:"
+    play_now:  "Одоо тогло"
+    im_a_parent:  "Би эцэг эх"
+    im_an_educator:  "Би сурган хүмүүжүүлэгч"
+    im_a_teacher:  "Би бол багш"
+    im_a_student:  "Би бол сурагч"
 #    learn_more: "Learn more"
 #    classroom_in_a_box: "A classroom in-a-box for teaching computer science."
 #    codecombat_is: "CodeCombat is a platform <strong>for students</strong> to learn computer science while playing through a real game."


Set subject ratio to half candels_2epoch, half goods_full

--- app/models/subject.coffee
+++ app/models/subject.coffee
@@ -45,23 +45,14 @@
       tree: SloanSinglebandTree

   @url: (params) -> @withParams "/projects/galaxy_zoo/groups/#{ params.surveyId }/subjects", limit: params.limit
+
   @randomSurveyId: ->
-    @::surveys.candels_2epoch.id
-    # n = Math.random()
-    # if n <= 0.33
-    #   @::surveys.candels_2epoch.id
-    # else if n <= 0.66
-    #   @::surveys.goods_full.id
-    # else
-    #   @::surveys.sloan_singleband.id
+    n = Math.random()
+    if n <= 0.5
+      @::surveys.candels_2epoch.id
+    else
+      @::surveys.goods_full.id

-    # return @::surveys.sloan.id if UserGroup.current
-    # n = Math.random()
-    # if n <= 0.10
-    #   @::surveys.sloan.id   # 10%
-    # else
-    #   @::surveys.ukidss.id  # 90%
-
   @next: ->
     if @current
       @current.destroy()
@@ -72,19 +63,14 @@

   @fetch: ->
     count = Config.subjectCache - @count()
-    idCounts = { }
-    idCounts[@::surveys.sloan.id] = 0
-    idCounts[@::surveys.candels.id] = 0
-    idCounts[@::surveys.ukidss.id] = 0
-    idCounts[@::surveys.ferengi.id] = 0
-    idCounts[@::surveys.sloan_singleband.id] = 0
-    idCounts[@::surveys.candels_2epoch.id] = 0
-    idCounts[@::surveys.goods_full.id] = 0
-    idCounts[@randomSurveyId()] += 1 for i in [1..count]
-
+    idCounts = {}
+    for i in [1..count]
+      survey = @randomSurveyId()
+      idCounts[survey] ||= 0
+      idCounts[survey] += 1
+
     hasTriggered = false
     for id, limit of idCounts
-      continue if limit is 0
       Api.get @url(surveyId: id, limit: limit), (results) =>
         @create result for result in results
         @current or= @first()


stray log

stray log

--- apps/about2/routes.coffee
+++ apps/about2/routes.coffee
@@ -58,7 +58,6 @@
     from: TWILIO_NUMBER
     body: IPHONE_APP_COPY
   , (err, data) ->
-    console.log err
     return res.json err.status or 400, { msg: err.message } if err
     res.send { msg: "success", data: data }


- [grunt] removed duojs task file

- [grunt] removed duojs task file

--- tasks/grunt-duojs.coffee
+++ tasks/grunt-duojs.coffee
@@ -1,13 +0,0 @@
-###
-Duo
-https://github.com/imyelo/grunt-duojs
-Comlipe duo.js components
-###
-module.exports = (grunt) ->
-  @config 'duojs',
-    build:
-      options:
-        root: '<%= path.source.scripts %>'
-        entry: 'main.js'
-        installTo: '../../<%= path.temp.root %>'
-        buildTo: '../../<%= path.build.scripts %>'


2014-03-13

--- tasks/sass-format.coffee
+++ tasks/sass-format.coffee
@@ -85,10 +85,23 @@
               #セレクタ記述
               if /^[^;]+;$/.test(text[i])
                 #インデントチェック
+                #タブ
                 if /^[\t]{1,}/.test(text[i])
                   msg += 'インデントがタブ'
+                #ホワイトスペース
                 if /^[ ]{1,}/.test(text[i])
                   msg += 'インデントがホワイトスペース'
+
+                #インデント個数チェック
+                num = 1
+                regex = new RegExp('^([ \t]{'+num+','+num+'}){1,}[^ \t]')
+
+                if regex.test(text[i])
+                  msg += 'インデント'+num+'個'
+                else
+                  msg += 'インデント指定通りじゃない'
+
+

                 console.log line+': '+msg+': '+text[i]
                 msg = ''


social: style: overindented

social: style: overindented

--- workers/social/lib/social/models/invitation.coffee
+++ workers/social/lib/social/models/invitation.coffee
@@ -414,32 +414,32 @@
                       @sendInviteEmail invite,client,customMessage,limit,callback

   @createViaGroup = secure (client, group, emails, callback=->)->
-      {delegate} = client.connection
-      emails.forEach (email)=>
-        selector =
-          inviteeEmail : email
-          group        : group.slug
-
-        JInvitation.one selector, (err, existingInvite)=>
-          return callback err if err
-          if existingInvite
-            @sendEmailForInviteViaGroup client, existingInvite, group, callback
-          else
-            code = @generateInvitationCode email, group.slug
-            invite = new JInvitation
-              code         : code
-              maxUses      : 1
-              inviteeEmail : email
-              origin       : ObjectRef(delegate)
-              group        : group.slug
-
-            invite.save (err)=>
-              if err then callback err
-              else
-                invite.addInvitedBy delegate, (err)=>
-                  if err then callback err
-                  else
-                    @sendEmailForInviteViaGroup client, invite, group, callback
+    {delegate} = client.connection
+    emails.forEach (email)=>
+      selector =
+        inviteeEmail : email
+        group        : group.slug
+
+      JInvitation.one selector, (err, existingInvite)=>
+        return callback err if err
+        if existingInvite
+          @sendEmailForInviteViaGroup client, existingInvite, group, callback
+        else
+          code = @generateInvitationCode email, group.slug
+          invite = new JInvitation
+            code         : code
+            maxUses      : 1
+            inviteeEmail : email
+            origin       : ObjectRef(delegate)
+            group        : group.slug
+
+          invite.save (err)=>
+            if err then callback err
+            else
+              invite.addInvitedBy delegate, (err)=>
+                if err then callback err
+                else
+                  @sendEmailForInviteViaGroup client, invite, group, callback

   redeem:secure ({connection:{delegate}}, callback=->)->
     operation = $inc: {uses: 1}


node: depracate uid

node: depracate uid

it was used for kontainer machine users

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -100,9 +100,6 @@
         validate    : JName.validateName
         set         : (value) -> value.toLowerCase()
       oldUsername   : String
-      uid           :
-        type        : Number
-        set         : Math.floor
       email         :
         type        : String
         validate    : JName.validateEmail


JUser: remove oauth information from JUser model

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -68,11 +68,6 @@
       username      : 'unique'
       email         : 'unique'
       sanitizedEmail: ['unique', 'sparse']
-      'foreignAuth.github.foreignId'   : 'ascending'
-      'foreignAuth.facebook.foreignId' : 'ascending'
-      'foreignAuth.google.foreignId'   : 'ascending'
-      'foreignAuth.linkedin.foreignId' : 'ascending'
-      'foreignAuth.twitter.foreignId'  : 'ascending'

     sharedEvents    :
       # do not share any events
@@ -170,22 +165,6 @@
         type        : Object
         default     : -> []

-      foreignAuth            :
-        gitlab               : Object
-        github               :
-          foreignId          : String
-          username           : String
-          token              : String
-          firstName          : String
-          lastName           : String
-          email              : String
-          scope              : String
-        facebook             :
-          foreignId          : String
-          username           : String
-          token              : String
-        linkedin             :
-          foreignId          : String
     relationships       :
       ownAccount        :
         targetType      : JAccount
@@ -238,7 +217,6 @@
         sshKeys             : []
         username            : username
         password            : createId()
-        foreignAuth         : {}
         onlineStatus        : 'offline'
         registeredAt        : new Date 0
         lastLoginDate       : new Date 0
@@ -876,14 +854,8 @@
           next()

       (next) ->
-        # updating user data after login
-        userUpdateData = { lastLoginDate : new Date }

         if session.foreignAuth
-          { foreignAuth } = user
-          foreignAuth   or= {}
-          foreignAuth     = extend foreignAuth, session.foreignAuth
-          userUpdateData.foreignAuth = foreignAuth

         userUpdateOptions =
           $set        : userUpdateData
@@ -898,14 +870,8 @@
           # p.s. we could do that in workers
           account.updateCounts()

-          if foreignAuth
-            providers = {}
-            Object.keys(foreignAuth).forEach (provider) ->
-              providers[provider] = yes
-
-            Tracker.identify user.username, { foreignAuth: providers }
-
           JLog.log { type: 'login', username , success: yes }
+
           next()

       (next) ->
@@ -1039,7 +1005,7 @@
   @createUser = (userInfo, callback) ->

     { username, email, password, passwordStatus,
-      firstName, lastName, foreignAuth, silence, emailFrequency } = userInfo
+      firstName, lastName, silence, emailFrequency } = userInfo

     if typeof username isnt 'string'
       return callback new KodingError 'Username must be a string!'
@@ -1089,8 +1055,6 @@
         emailFrequency   : emailFrequency
       }

-      user.foreignAuth = foreignAuth  if foreignAuth
-
       user.save (err) ->

         if err
@@ -1118,22 +1082,13 @@
             else callback null, user, account

-  @fetchUserByProvider = (provider, session, callback) ->
-
-    { foreignAuth } = session
-    unless foreignAuth?[provider]?.foreignId
-      return callback new KodingError "No foreignAuth:#{provider} info in session"
-
-    query                                      = {}
-    query["foreignAuth.#{provider}.foreignId"] = foreignAuth[provider].foreignId
-
-    JUser.one query, callback
-
-
   @authenticateWithOauth = secure (client, resp, callback) ->

+    unless client
+      return callback new KodingError 'Couldn\'t restore your session!'
+
     { isUserLoggedIn, provider } = resp
-    { sessionToken }             = client
+    { sessionToken } = client

     JSession.one { clientId: sessionToken }, (err, session) =>
       return callback new KodingError err  if err
@@ -1269,8 +1224,7 @@
       email
       recaptcha
       disableCaptcha
-      userFormData
-      foreignAuthType } = options
+      userFormData } = options

     queue = [

@@ -1278,7 +1232,7 @@
         # verifying recaptcha if enabled
         return next()  if disableCaptcha or not KONFIG.recaptcha.enabled

-        JUser.verifyRecaptcha recaptcha, { foreignAuthType, slug }, next
+        JUser.verifyRecaptcha recaptcha, { slug }, next

       (next) ->
         JUser.validateAll userFormData, next
@@ -1446,7 +1400,7 @@

   validateConvert = (options, callback) ->

-    { client, userFormData, foreignAuthType, skipAllowedDomainCheck } = options
+    { client, userFormData, skipAllowedDomainCheck } = options
     { slug, email, invitationToken, recaptcha, disableCaptcha } = userFormData

     invitation = null
@@ -1454,7 +1408,7 @@
     queue = [

       (next) ->
-        params = { slug, email, recaptcha, disableCaptcha, userFormData, foreignAuthType }
+        params = { slug, email, recaptcha, disableCaptcha, userFormData }
         verifyUser params, next

       (next) ->
@@ -1568,7 +1522,6 @@
     error            = null
     newToken         = null
     invitation       = null
-    foreignAuthType  = null
     subscription     = null

     queue = [
@@ -1591,7 +1544,7 @@
           next()

       (next) ->
-        options = { client, userFormData, foreignAuthType, skipAllowedDomainCheck }
+        options = { client, userFormData, skipAllowedDomainCheck }
         validateConvert options, (err, data) ->
           return next err  if err
           { invitation } = data
@@ -1993,55 +1946,12 @@

   unlinkOAuths: (callback) ->

-    @update { $unset: { foreignAuth:1 , foreignAuthType:1 } }, (err) =>
+    @update { $unset: { foreignAuth:1 } }, (err) =>
       return callback err  if err

       @fetchOwnAccount (err, account) ->
         return callback err  if err
         account.unstoreAll callback
-
-
-  @persistOauthInfo: (username, clientId, callback) ->
-
-    JSession.fetchOAuthInfo clientId, (err, foreignAuthInfo) =>
-      return callback err   if err
-      return callback null  unless foreignAuthInfo
-      return callback null  unless foreignAuthInfo.session
-
-      @saveOauthToUser foreignAuthInfo, username, (err) =>
-        return callback err  if err
-
-        do (foreignAuth = {}) ->
-          { foreignAuthType } = foreignAuthInfo
-          foreignAuth[foreignAuthType] = yes
-          Tracker.identify username, { foreignAuth }
-
-        JSession.clearOauthInfo foreignAuthInfo.session, (err) =>
-          return callback err  if err
-
-          @copyPublicOauthToAccount username, foreignAuthInfo, (err, resp = {}) ->
-            return callback err  if err
-            { session: { returnUrl } } = foreignAuthInfo
-            resp.returnUrl = returnUrl  if returnUrl
-            return callback null, resp
-
-
-  @saveOauthToUser: ({ foreignAuth, foreignAuthType }, username, callback) ->
-
-    query = {}
-    query["foreignAuth.#{foreignAuthType}"] = foreignAuth[foreignAuthType]
-
-    @update { username }, { $set: query }, callback
-
-
-  @copyPublicOauthToAccount: (username, { foreignAuth, foreignAuthType }, callback) ->
-
-    JAccount.one { 'profile.nickname' : username }, (err, account) ->
-      return callback err  if err
-
-      name    = "ext|profile|#{foreignAuthType}"
-      content = foreignAuth[foreignAuthType].profile
-      account._store { name, content }, callback

   @setSSHKeys: secure (client, sshKeys, callback) ->


Indentation Killed The Authentication.

Indentation Killed The Authentication.

--- scripts/dynamic.coffee
+++ scripts/dynamic.coffee
@@ -6,16 +6,22 @@

 module.exports = (robot) ->
     robot.respond /shoutout ([a-zA-Z0-9_]*)/i, (msg) ->
-        query = msg.match[1]
-        robot.http("https://api.twitch.tv/kraken/channels/#{query}")
-            .get() (err, res, body) ->
-                streamer = JSON.parse(body)
+        if robot.auth.hasRole(msg.envelope.user, ['admin', 'moderator'])
+            query = msg.match[1]
+            robot.http("https://api.twitch.tv/kraken/channels/#{query}")
+                .get() (err, res, body) ->
+                    streamer = JSON.parse(body)

-                if streamer.status == 404
-                    msg.send "That user doesn’t appear to exist, please check your spelling!"
-                    return
+                    if streamer.status == 404
+                        msg.send "That user doesn’t appear to exist, please check your spelling!"
+                        return

-                shout = "Check out the awesome #{streamer.display_name} at #{streamer.url}!"
-                if streamer.game
-                    shout = "#{shout} They’ve recently been playing #{streamer.game}."
-                msg.send shout
+                    shout = "Check out the awesome #{streamer.display_name} at #{streamer.url}!"
+                    if streamer.game
+                        shout = "#{shout} They’ve recently been playing #{streamer.game}."
+                    msg.send shout
+
+            return
+
+        #If user doesn’t have permission to shoutout
+        msg.send "Hey #{msg.envelope.user.name}, only mods and Masonest can do that!"


Added Tweet command. Bitly credit goes to Bryan.

--- scripts/dynamic.coffee
+++ scripts/dynamic.coffee
@@ -25,3 +25,37 @@

         #If user doesn’t have permission to shoutout
         msg.send "Hey #{msg.envelope.user.name}, only mods and Masonest can do that!"
+
+    robot.respond /(ctt|tweet)$/i, (msg) ->
+        message = "If you’re enjoying the stream, please share it with your friends!"
+
+        robot.http("https://api.twitch.tv/kraken/channels/masonest")
+            .get() (err, res, body) ->
+                streamer = JSON.parse(body)
+                game = if streamer.game then "play some #{streamer.game} " else ""
+                tweet = "Come watch @masonest_ #{game}at http://twitch.tv/masonest and hang out in the chat!"
+                tweet = encodeURIComponent(tweet)
+                url = "https://twitter.com/intent/tweet?text=#{tweet}&source=clicktotweet"
+
+                # See if we’ve already shortened this before.
+                msg.http("https://api-ssl.bitly.com/v3/link/lookup")
+                    .query
+                        access_token: process.env.HUBOT_BITLY_ACCESS_TOKEN
+                        longUrl: url
+                        format: "json"
+                    .get() (err, res, body) ->
+                        response = JSON.parse body
+                        if response.data.link_lookup.aggregate_link
+                            msg.send "#{message} #{response.data.link_lookup.aggregate_link}."
+                            return
+
+                # After gathering dynamic link content, send to bitly.
+                msg.http("https://api-ssl.bitly.com/v3/shorten")
+                    .query
+                        access_token: process.env.HUBOT_BITLY_ACCESS_TOKEN
+                        longUrl: url
+                        format: "json"
+                    .get() (err, res, body) ->
+                        response = JSON.parse body
+                        response = if response.status_code is 200 then response.data.url else response.status_txt
+                        msg.send "#{message} #{response}."


noise reduction

noise reduction

--- scripts/example.coffee
+++ scripts/example.coffee
@@ -12,34 +12,33 @@

    robot.hear /badger/i, (res) ->
      res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"
-
+
    robot.respond /open the (.*) doors/i, (res) ->
      doorType = res.match[1]
      if doorType is "pod bay"
        res.reply "I'm afraid I can't let you do that."
      else
        res.reply "Opening #{doorType} doors"
-
+
    robot.hear /I like pie/i, (res) ->
     res.emote "makes a freshly baked pie"
-
+
    lulz = ['lol', 'rofl', 'lmao']
-
+
    robot.respond /lulz/i, (res) ->
     res.send res.random lulz
-
+
    robot.topic (res) ->
      res.send "#{res.message.text}? That's a Paddlin'"
-
-
-   enterReplies = ['Hi', 'Target Acquired', 'Firing', 'Hello friend.', 'Gotcha', 'I see you']
-   leaveReplies = ['Are you still there?', 'Target lost', 'Searching']
-
-   robot.enter (res) ->
-     res.send res.random enterReplies
-   robot.leave (res) ->
-     res.send res.random leaveReplies
-
+
+
+   # enterReplies = ['Hi', 'Target Acquired', 'Firing', 'Hello friend.', 'Gotcha', 'I see you']
+   # leaveReplies = ['Are you still there?', 'Target lost', 'Searching']
+   # robot.enter (res) ->
+   #   res.send res.random enterReplies
+   # robot.leave (res) ->
+   #   res.send res.random leaveReplies
+
   # answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING
   #
   # robot.respond /what is the answer to the ultimate question of life/, (res) ->
@@ -52,19 +51,19 @@
      setTimeout () ->
        res.send "Who you calling 'slow'?"
      , 60 * 1000
-
+
    annoyIntervalId = null
-
+
    robot.respond /annoy me/, (res) ->
      if annoyIntervalId
        res.send "AAAAAAAAAAAEEEEEEEEEEEEEEEEEEEEEEEEIIIIIIIIHHHHHHHHHH"
        return
-
+
      res.send "Hey, want to hear the most annoying sound in the world?"
      annoyIntervalId = setInterval () ->
        res.send "AAAAAAAAAAAEEEEEEEEEEEEEEEEEEEEEEEEIIIIIIIIHHHHHHHHHH"
      , 1000
-
+
    robot.respond /unannoy me/, (res) ->
      if annoyIntervalId
        res.send "GUYS, GUYS, GUYS!"
@@ -72,8 +71,8 @@
        annoyIntervalId = null
      else
        res.send "Not annoying you right now, am I?"
-
-
+
+
   # robot.router.post '/hubot/chatsecrets/:room', (req, res) ->
   #   room   = req.params.room
   #   data   = JSON.parse req.body.payload
@@ -85,7 +84,7 @@
   #
    robot.error (err, res) ->
      robot.logger.error "DOES NOT COMPUTE"
-
+
      if res?
        res.reply "DOES NOT COMPUTE"
   #


commit

commit

--- scripts/example.coffee
+++ scripts/example.coffee
@@ -10,10 +10,7 @@

 module.exports = (robot) ->

-   robot.hear /make it rain/i, (msg) ->
-     msg.send "https://s3.amazonaws.com/uploads.hipchat.com/12562/184609/xdhwG85hEGYKVeR/rainingkev-2.gif"
-
-   robot.hear /making it rain/i, (msg) ->
+   robot.hear /make it rain|making it rain|made it rain/i, (msg) ->
      msg.send "https://s3.amazonaws.com/uploads.hipchat.com/12562/184609/xdhwG85hEGYKVeR/rainingkev-2.gif"

    robot.hear /rain bomb( (\d+))?/i, (msg) ->


More mrkdwn fun with slack attachment

More mrkdwn fun with slack attachment

--- scripts/pudding.coffee
+++ scripts/pudding.coffee
@@ -185,6 +185,7 @@
           title: "#{site} #{env}"
           value: format_instance_totals_in_site_env(site, env, instances)
           short: true
+          mrkdwn_in: ['title', 'value', 'text']

     payload =
       message: msg.message
@@ -194,10 +195,8 @@
         pretext: "All _#{default_role}_ instances"
         color: '#77cc77'
         fields: fields
-        mrkdwn_in: ['fields', 'pretext', 'title']
+        mrkdwn_in: ['fallback', 'pretext']
       username: robot.name
-      mrkdwn_in: ['fields', 'pretext', 'title']
-      mrkdwn: true

     robot.emit 'slack.attachment', payload


fix getAllocations methods

fix getAllocations methods

--- server/methods/userGetAllocations.coffee
+++ server/methods/userGetAllocations.coffee
@@ -2,7 +2,7 @@

 	getAllocationsWeek: (userId, week) ->
 		check userId, String
-		check week. String
+		check week String

 		start = moment(week).format('YYYYDDDD')
 		end = moment(week).endOf('isoWeek').format('YYYYDDDD')
@@ -19,7 +19,7 @@

 	getAllocationsLastN: (userId, days) ->
 		check userId, String
-		check days. Number
+		check days Number

 		end = moment().format('YYYYDDDD')
 		start = end - days


focus only when needed and when switching between different questions, also dont need additional scrolling code

--- shared/src/components/exercise/mode.cjsx
+++ shared/src/components/exercise/mode.cjsx
@@ -26,12 +26,10 @@
     answerId: answer_id

   componentDidMount: ->
-    {mode} = @props
-    @setFreeResponseFocusState() if mode is 'free-response'
+    @setFreeResponseFocusState()

   componentDidUpdate: (prevProps) ->
-    {mode, focus} = prevProps
-    @setFreeResponseFocusState() if mode is 'free-response'
+    @setFreeResponseFocusState(prevProps)

   componentWillReceiveProps: (nextProps) ->
     {free_response, answer_id, cachedFreeResponse} = nextProps
@@ -44,13 +42,19 @@

     @setState(nextAnswers) unless _.isEmpty(nextAnswers)

-  setFreeResponseFocusState: ->
-    {focus} = @props
+  setFreeResponseFocusState: (prevProps = {}) ->
+    {mode, focus, id} = prevProps
+    return unless (
+      @props.mode is 'free-response' and (
+        focus isnt @props.focus or
+        id isnt @props.id
+      )
+    )
+
     el = ReactDOM.findDOMNode(@refs.freeResponse)
     if el
-      if focus
+      if @props.focus
         el.focus?()
-        window.scrollTo(0, 0);
       else
         el.blur?()


improve activateFirstTab

improve activateFirstTab

--- app/lib/sub-nav.coffee
+++ app/lib/sub-nav.coffee
@@ -22,8 +22,8 @@
       @activatePage(page, e.target.name)

   activateFirstTab: (page) ->
-    firstTab = $(".sub-nav-#{page} button:nth-child(1)").addClass("active").attr('name')
-    @el.find(".sub-nav-#{page}-#{firstTab}:nth-child(1)").siblings().hide()
+    firstSection = $(".sub-nav-#{page} button:nth-child(1)").attr('name')
+    @activatePage(page, firstSection)

   showSection: (page, section) ->
     @el.find(".sub-nav-#{page}-#{section}")


debug attachment saving

debug attachment saving

--- app/models/mail.coffee
+++ app/models/mail.coffee
@@ -4,28 +4,23 @@
 # Get attachments returned by mailparser as parameter. Save them as couchdb
 # attachments wrapped in a dedicated model.
 Mail::saveAttachments = (attachments, callback) ->
-    if attachments?
-        attachFuncs = []

-        for attachment in attachments
-            params =
-                cid: attachment.contentId
-                fileName: attachment.fileName
-                contentType: attachment.contentType
-                length: attachment.length
-                mail_id: @id
-                checksum: attachment.checksum
+    if attachments? and attachments.length > 0
+        attachment = attachments.pop()
+        params =
+            cid: attachment.contentId
+            fileName: attachment.fileName
+            contentType: attachment.contentType
+            length: attachment.length
+            mail_id: @id
+            checksum: attachment.checksum
+            mailbox: @mailbox
+        Attachment.create params, (error, attach) =>
+            fileName =  "/tmp/#{attachment.fileName}"
+            fs.writeFile fileName, attachment.content, (error) =>
+                attach.attachFile fileName, (error) =>
+                    fs.unlink fileName, (error) =>
+                        @saveAttachments attachments, callback

-            attachFunc = (callback) ->
-                Attachment.create params, (error, attach) ->
-                    fileName =  "/tmp/#{attachment.fileName}"
-                    fs.writeFile fileName, attachment.content, (error) ->
-                        attach.attachFile fileName, (error) ->
-                            fs.unlink fileName, callback
-
-            attachFuncs.push attachFunc
-
-        async.series attachFuncs, callback
-
     else
         callback()


Added the installProd tests

Added the installProd tests

They're basically identical, i need to think of a way to test
them both without duplicating so much code.

--- test/deps/install.coffee
+++ test/deps/install.coffee
@@ -62,6 +62,57 @@

+describe 'installProd()', ->
+  install     = null
+  installProd = null
+  opts        = null
+  before ->
+    install       = rewire '../../lib/deps/install'
+    {installProd} = install
+    opts =
+      node  : true
+      #For the future
+      #bower : true
+      #pip   : true
+      #gem   : true
+
+  describe 'with no package file', ->
+    before ->
+      install.__set__ 'installNodeProd', (ipath, opts, callback) ->
+        callback (new Error 'not found'), false, []
+
+    it 'should bail with an error', ->
+      installProd 'fake', opts, (err, packages) ->
+        should.exist err
+        err.message.should.match /not found/
+        packages.length.should.equal 0
+
+    # Commented out until multiple installers are added
+    #it 'should not call installers after the failure'
+
+  describe 'with no dependencies', ->
+    before ->
+      install.__set__ 'installNodeProd', (ipath, opts, callback) ->
+        callback null, true, []
+
+    it 'should show installed with no packages', ->
+      installProd 'fake', opts, (err, packages) ->
+        should.not.exist err
+        packages.length.should.equal 0
+
+  describe 'on success', ->
+    before ->
+      install.__set__ 'installNodeProd', (ipath, opts, callback) ->
+        callback null, true, ['some@dep']
+
+    it 'should show installed with all packages concated together', ->
+      installProd 'fake', opts, (err, packages) ->
+        should.not.exist err
+        packages.length.should.equal 1
+
+
+
+
 describe 'installNodeDev()', ->
   installNodeDev  = null
   before -> {installNodeDev} = require '../../lib/deps/install'


Added dot at the end of error string.

Added dot at the end of error string.

--- server/accounts.coffee
+++ server/accounts.coffee
@@ -61,7 +61,7 @@
     ,
       $set:
         username: username
-    throw new Meteor.Error 400, "Username already set" unless updatedCount is 1
+    throw new Meteor.Error 400, "Username already set." unless updatedCount is 1

     return # Make sure CoffeeScript does not return anything


Sim: Support JSON datatype a bit better.

--- server/database.coffee
+++ server/database.coffee
@@ -1,4 +1,5 @@
 Bookshelf = require('bookshelf')
+{_} = require('underscore')
 config = require('../knex_config').database

 Bookshelf.PG = PG = Bookshelf.initialize(config)
@@ -7,11 +8,15 @@
   tableName: 'teams'
   hasTimestamps: ['created_at', 'updated_at']

-  toJSON: -> {
+  toJSON: ->
+    contents = @get('contents')
+    {
       id: @id
       name: @get('name')
       generation: @get('generation')
-      pokemon: JSON.parse(@get('contents'))
+      # Postgres 9.2+ support the JSON datatype. Other versions/DBs do not.
+      # So if the JSON data type is supported, then loading will load as JSON.
+      pokemon: (if _.isObject(contents) then contents else JSON.parse(contents))
     }

 Teams = PG.Collection.extend


improve transitions

improve transitions

--- app/transitions.coffee
+++ app/transitions.coffee
@@ -1,7 +1,14 @@
 Transitions = ->
   @transition(
-    @fromRoute(null,'about', 'influences', 'projects', 'projects.index', 'project', 'contact'),
-    @toRoute('about', 'influences', 'projects', 'projects.index', 'project', 'contact'),
+    @fromRoute(null, 'about', 'influences', 'projects', 'contact'),
+    @toRoute('about', 'influences', 'projects', 'contact'),
+    @use('crossFade'),
+    @reverse('crossFade')
+  )
+
+  @transition(
+    @fromRoute('projects.index'),
+    @toRoute('project'),
     @use('crossFade'),
     @reverse('crossFade')
   )


Test Number object behavior for componentsOf

--- test/test-english.coffee
+++ test/test-english.coffee
@@ -142,3 +142,8 @@
     components.total.seconds.should.equal '439564 seconds'
     components.milliseconds.should.equal '20 milliseconds'
     components.total.milliseconds.should.equal '439564020 milliseconds'
+
+  it 'grabs the components and keeps the Number objects intact', ->
+    duration = new Number(420420)
+    componentsOf duration
+    duration.valueOf().should.equal 420420


Nodejs: metrics: remove last slash of metrics name in server/datadog.coffee

--- servers/datadog.coffee
+++ servers/datadog.coffee
@@ -11,9 +11,10 @@
   @sanitizeMetricName : (string) ->

     return string
-      .replace /[\/-]/g,               '.'     # replace all / with .
-      .replace /\.{2,}/g,              '.'     # remove adjacent dots
-      .replace /[^a-zA-Z0-9_\.]/g,     '_'     # replace invalid chars with _
+      .replace /\/$/g,                 ''   # removing last /
+      .replace /[\/-]/g,               '.'  # replace all / with .
+      .replace /\.{2,}/g,              '.'  # remove adjacent dots
+      .replace /[^a-zA-Z0-9_\.]/g,     '_'  # replace invalid characters with _

   @generateName : (req) ->


detach child nodes from CompositeModelView prior to calling jQuery html in order to prevent events from being unregistered from child view event handlers - update CompositeModelForm after a file upload roundtrips

--- guts.coffee
+++ guts.coffee
@@ -138,6 +138,7 @@

     @_rendered = true
     template_result = render do @get_template, context
+    orphans = @$el.children().detach()
     @$el.html(template_result)

     # Put the children back in their place
@@ -200,6 +201,7 @@

           @model.set_file_field file_element.name, file
           @model.save()
+          @listenToOnce @model, 'change', @rerender
     return


atualiza referência do sellerId quando monta o link do by-button no sku selector

--- src/coffee/portal-sku-selector.coffee
+++ src/coffee/portal-sku-selector.coffee
@@ -321,11 +321,11 @@
 				@showConfirmButton(selectedSku)
 			else
 				$(window).trigger 'modalHide.vtex'
-				$.get($.skuSelector.getAddUrlForSku(selectedSku.sku, 1, 1, @productData.salesChannel, false))
+				$.get($.skuSelector.getAddUrlForSku(selectedSku.sku, sku.sellerId, 1, @productData.salesChannel, false))
 				.done (data) =>
 						$(window).trigger 'productAddedToCart'
 				.fail (jqXHR, status) =>
-						window.location.href = $.skuSelector.getAddUrlForSku(selectedSku.sku, 1, @productData.salesChannel)
+						window.location.href = $.skuSelector.getAddUrlForSku(selectedSku.sku, sku.sellerId, 1, @productData.salesChannel)
 				return false
 		else
 			@findwarning().show().text('Por favor, escolha: ' + @findUndefinedDimensions()[0].name)


Disable the broken Sarcoma grade test case and add a FIXME.

--- test/unit/tnmSpec.coffee
+++ test/unit/tnmSpec.coffee
@@ -1,4 +1,4 @@
-define ['ngmocks', 'tnm', 'helpers'], ->
+define ['ngmocks', 'tnm', 'helpers'], ->
   describe 'Unit Testing the TNM Service', ->
     # The qiprofile TNM factory.
     TNM = null
@@ -123,7 +123,10 @@
           else
             3

-        it 'should calculate the summary grade', ->
+        # FIXME - the test case below once passed but now fails.
+        # The test is disabled by using xit rather than it.
+        # Change xit to it, fix the problem and remove this comment.
+        xit 'should calculate the summary grade', ->
           for df in [1..3]
             for mc in [1..3]
               for nc in [1..2]


动态加载版本

动态加载版本

--- plugins/help.coffee
+++ plugins/help.coffee
@@ -1,13 +1,18 @@
 HELP_INFO = """
-    version         #版本信息和关于
+    version/about   #版本信息和关于
     plugins         #查看载入的插件
     time            #显示时间
-    echo            #重复后面的话
-    help            #本内容
+    echo 爱你        #重复后面的话
+    help            #本内容
 """

+fs = require 'fs'
+Path = require 'path'
+file_path = Path.join __dirname, "..", "package.json"
+bundle = JSON.parse( fs.readFileSync file_path )
+
 VERSION_INFO = """
-    v1.0.0 qqbot
+    v#{bundle.version} qqbot
     http://github.com/xhan/qqbot
     本工具还由 糗事百科 热血赞助！
 """
@@ -26,8 +31,8 @@
     if content.match /^help$/i
         send HELP_INFO

-    if content.match /^VERSION$/i
-        send VERSION_INFO
+    if content.match /^VERSION|ABOUT$/i
+      send VERSION_INFO

     if content.match /^plugins$/i
         send "插件列表：\n" + robot.dispatcher.plugins.join('\r\n')


needless to check in array

needless to check in array

--- dbserver.coffee
+++ dbserver.coffee
@@ -53,16 +53,13 @@
 			console.log(err) if err

 			iter = (prev, curr) ->
-				if curr.BSSID of weights
-					currWeight = weights[curr.BSSID]
-					return [
-						prev[0] + (curr.x * currWeight),
-						prev[1] + (curr.y * currWeight),
-						prev[2] + (curr.z * currWeight),
-						prev[3] + currWeight
-					]
-				else
-					return prev
+				currWeight = weights[curr.BSSID]
+				return [
+					prev[0] + (curr.x * currWeight),
+					prev[1] + (curr.y * currWeight),
+					prev[2] + (curr.z * currWeight),
+					prev[3] + currWeight
+				]

 			merge = docs.reduce(iter, [0, 0, 0, 0])


fix new cs-resoruce with value

fix new cs-resoruce with value

--- src/cs-resource/cs-resource.js.coffee
+++ src/cs-resource/cs-resource.js.coffee
@@ -44,7 +44,7 @@

     @$new: (opts = {}) ->
       if opts.value
-        value_object = opts.value
+        value_object = angular.copy(opts.value)
         value_object.relationships ||= {}
         value_object.attributes ||= {}
         value_object.type ||= @descriptor.type


Modal: Added forgotten @export tag for destroy method.

--- src/lib/components/modal/Modal.coffee
+++ src/lib/components/modal/Modal.coffee
@@ -169,6 +169,8 @@
     event handler binded to window to set positions correctly. If your modal
     don't closable or you want to handle close action programatically, when you
     want to remove the modal you should call this method.
+
+    @export
   ###
   destroy: ->
     @overlay?.removeFromDocument()


testing that object contracts correctly handle null values (blame vs error)

--- test/contracts.coffee
+++ test/contracts.coffee
@@ -450,3 +450,10 @@
   throws (-> getData [null, "string"])
   throws (-> getData [{},1,2,3])
   throws (-> getData {test:[1,2,3]})
+
+test "null values with obj contracts", ->
+  a :: ({a: Str, b: Str}) -> Any
+  a = (b) ->
+      console.log b
+
+  blames (-> a null)


HulkHogan refactored.

HulkHogan refactored.

--- hulk.coffee
+++ hulk.coffee
@@ -1,66 +1,70 @@
-{join} = require 'path'
+class HulkHogan
+	parsePartials : (source)->  # Return list of patial filenames in the source.
+		{scan} = require 'hogan.js'
+		result = []
+		scanned = scan source
+		for item in scanned
+			if item.tag is '>'
+				result.push item.n
+		return result

-exports.parsePartials = (source)->  # Return list of patial filenames in the source.
-	{scan} = require 'hogan.js'
-	result = []
-	scanned = scan source
-	for item in scanned
-		if item.tag is '>'
-			result.push item.n
-	return result
+
+	_readFile : (file)->
+		{readFileSync} = require 'fs'
+		return readFileSync(file).toString() # TODO better way to read file? especially large ones.

-readFile = (file)->
-	{readFileSync} = require 'fs'
-	return readFileSync(file).toString() # TODO better way to read file, especially large ones.
+
+	_makePartials : (partials, list, root, defaultEngine)->
+		{join} = require 'path'
+		{existsSync} = require 'path'

-{existsSync} = require 'path'
-makePartials = (partials, list, root, defaultEngine)->
-	for file in list
-		sublist = []
-		source = null
+		for file in list
+			sublist = []
+			source = null

-		if file not of partials
-			filepath = join root, file
+			if file not of partials
+				filepath = join root, file

-			if existsSync filepath
-				source = readFile filepath
-			else if defaultEngine and existsSync filepath+=".#{defaultEngine}"
-				source = readFile filepath
+				if existsSync filepath
+					source = @_readFile filepath
+				else if defaultEngine and existsSync filepath+=".#{defaultEngine}"
+					source = @_readFile filepath

-			if source
-				partials[file] = source
+				if source
+					partials[file] = source

-				sublist = exports.parsePartials source
+					sublist = @parsePartials source

-				if sublist.length
-					makePartials partials, sublist, root, defaultEngine
-
+					if sublist.length
+						@_makePartials partials, sublist, root, defaultEngine
+
+

+	compile : (source='', options)->
+		hogan = require 'hogan.js'
+		compiled = hogan.compile source

-compile = exports.compile = (source='', options)->
-	hogan = require 'hogan.js'
-	compiled = hogan.compile source
+		partials = {}
+		# Get Partials #
+		partial_files = @parsePartials source

-	partials = {}
-	# Get Partials #
-	partial_files = exports.parsePartials source
+		if partial_files.length
+			@_makePartials partials, partial_files, options.root, options.defaultEngine

-	if partial_files.length
-		makePartials partials, partial_files, options.root, options.defaultEngine
+		return ->
+			return compiled.render options, partials

-	return ->
-		return compiled.render options, partials
+
+	__express : (filename, options, callback) ->
+		# add support for Express 3.x templating scheme
+		# in Express use like this:
+		#
+		#		app.engine 'html', hogan.__express
+		#		app.set 'view engine', 'html'
+		#
+		source = @_readFile(filename)
+		# pass options to compile method to support partials
+		compiled = @compile(source, options)
+		callback(null, compiled(options))

-# add support for Express 3.x templating scheme
-# in Express use like this:
-#
-#		app.engine 'html', hogan.__express
-#		app.set 'view engine', 'html'
-#
-exports.__express = (filename, options, callback) ->
-  source = readFile(filename)
- 	# pass options to compile method to support partials
-  compiled = compile(source, options)
-  callback(null, compiled(options))
-
-
+module.exports = new HulkHogan


Create a model

Create a model

--- snippets/eloquent.cson
+++ snippets/eloquent.cson
@@ -1,4 +1,17 @@
 '.source.php':
+
+    'Create a model':
+        'prefix': 'model',
+        'body': """
+            namespace App;
+
+            use Illuminate\Database\Eloquent\Model;
+
+            class $1 extends Model
+            {
+                protected $guarded = [];
+            }
+        """

     # Has one
     '"Has One" Relationship':


Delete AppVersion.coffee

Delete AppVersion.coffee

--- app/assets/javascripts/directives/AppVersion.coffee
+++ app/assets/javascripts/directives/AppVersion.coffee
@@ -1,6 +0,0 @@
-
-
-directivesModule.directive('appVersion', ['version', (version) ->
-        (scope, elm, attrs) ->
-            elm.text(version)
-    ])


Refactored the view to use a helper function for time conversion

--- app/assets/javascripts/views/patient_view.js.coffee
+++ app/assets/javascripts/views/patient_view.js.coffee
@@ -1,5 +1,7 @@
 class Thorax.Views.PatientView extends Thorax.View
   template: JST['patients/show']
-  formatted_effective_time: -> moment(@model.get('effective_time')).format('MM/DD/YYYY') if @model.get('effective_time')?
-  formatted_birthdate: -> moment(@model.get('birthdate')).format('MM/DD/YYYY') if @model.get('birthdate')?
+  formatted_effective_time: -> format_time @model.get('effective_time')
+  formatted_birthdate: -> format_time @model.get('birthdate')

+  # Helper function for date/time conversion
+  format_time = (time) -> moment(time).format('MM/DD/YYYY') if time


update pivotalstorylisten to remove xml2js dependency, use pivotal API v5, and work again

--- src/scripts/pivotalstorylisten.coffee
+++ src/scripts/pivotalstorylisten.coffee
@@ -14,29 +14,28 @@
 #   christianchristensen

 module.exports = (robot) ->
-   robot.hear /(sid-|SID-|pivotaltracker.com\/story\/show)/i, (msg) ->
-    Parser = require("xml2js").Parser
+  robot.hear /(sid-|SID-|pivotaltracker.com\/story\/show)/i, (msg) ->
     token = process.env.HUBOT_PIVOTAL_TOKEN
     story_id = msg.message.text.match(/\d+$/) # look for some numbers in the string

-    msg.http("http://www.pivotaltracker.com/services/v3/projects").headers("X-TrackerToken": token).get() (err, res, body) ->
-      if err
-        msg.send "Pivotal says: #{err}"
-        return
-      (new Parser).parseString body, (err, json)->
-        for project in json.project
-          msg.http("https://www.pivotaltracker.com/services/v3/projects/#{project.id}/stories/#{story_id}").headers("X-TrackerToken": token).get() (err, res, body) ->
-            if err
-              msg.send "Pivotal says: #{err}"
-              return
-            if res.statusCode != 500
-              (new Parser).parseString body, (err, story)->
-                if !story.id
-                  return
-                message = "##{story.id['#']} #{story.name}"
-                message += " (#{story.owned_by})" if story.owned_by
-                message += " is #{story.current_state}" if story.current_state && story.current_state != "unstarted"
-                msg.send message
-                storyReturned = true
-                return
-    return
+    msg.http("https://www.pivotaltracker.com/services/v5/projects").headers("X-TrackerToken": token).get() (err, res, body) ->
+      return msg.send "Pivotal says: #{err}" if err
+
+      try
+        projects = JSON.parse(body)
+      catch e
+        return msg.send "Error parsing pivotal projects body: #{e}"
+
+      for project in projects
+        msg.http("https://www.pivotaltracker.com/services/v5/projects/#{project.id}/stories/#{story_id}").headers("X-TrackerToken": token).get() (err, res, body) ->
+          return msg.send "Pivotal says: #{err}" if err
+          return if res.statusCode == 404 # No story found in this project
+
+          try
+            story = JSON.parse(body)
+          catch e
+            return msg.send "Error parsing pivotal story body: #{e}"
+
+          message = "##{story.id} #{story.name}"
+          message += " is #{story.current_state}" if story.current_state && story.current_state != "unstarted"
+          msg.send message


fix typo

fix typo

--- src/scripts/team-city-listener.coffee
+++ src/scripts/team-city-listener.coffee
@@ -15,7 +15,7 @@
 #   None
 #
 # Notes:
-#   All the properties aviable on the build object can be found at the properties list at the top of this file:
+#   All the properties available on the build object can be found at the properties list at the top of this file:
 #   http://sourceforge.net/apps/trac/tcplugins/browser/tcWebHooks/trunk/src/main/java/webhook/teamcity/payload/format/WebHookPayloadJsonContent.java
 #
 # Author:


added example code for static final #26

added example code for static final #26

--- src/parser/java-parser.coffee
+++ src/parser/java-parser.coffee
@@ -124,12 +124,19 @@
       column: [
         {
           key: "allcaps", display: "Constant name is all caps with underscore(_)",
-          code: "final String FOO_BAR = \"\";"
+          code: """
+                final String FOO_BAR = \"baz\";
+
+                static final String FOO_BAR = \"baz\";
+                """
         }
         {
           key: "notallcaps", display: "Constant name is not all caps",
-          code: "final String foobar = \"\";"
-
+          code: """
+                final String foobar = \"baz\";
+
+                static final String foobar = \"baz\";
+                """
         }
       ]
       allcaps: 0


Simplify spec :sparkles:

Simplify spec :sparkles:

--- spec/latex-spec.coffee
+++ spec/latex-spec.coffee
@@ -75,9 +75,7 @@
       helpers.overridePlatform(originalPlatform)

     it "supports OS X", ->
-      ExpectedOpener = require '../lib/openers/preview-opener'
-
       helpers.overridePlatform('darwin')
       opener = latex.getOpener()

-      expect(opener).toEqual(new ExpectedOpener())
+      expect(opener.constructor.name).toEqual('PreviewOpener')


Added sorting

Added sorting

--- src/pipe/library/index.coffee
+++ src/pipe/library/index.coffee
@@ -2,6 +2,7 @@
 config = require('../../config')
 util = require('../../util')
 umd = require('../umd')
+sort = require('../sort')

 formatName = (name) ->
   name.replace(/-(.)/, (match, x) -> x.toUpperCase())
@@ -14,6 +15,7 @@
     namespace: undefined
     isPlugin: undefined
     umd: {}
+    sort: {}
   }
   (options) ->
     name ?= util.loadPackageJson().name
@@ -21,6 +23,7 @@
     options.namespace ?= options.exports

     return lib.pipe.lazypipe()
+    .pipe -> sort(options.sort)
     .pipe -> lib.pipe.concat("#{name}.coffee")
     .pipe -> lib.metadata.data((file) ->
       file.data ?= {}


change loop order

change loop order

--- atmospheric/002-accumulated-heat/accumulator.coffee
+++ atmospheric/002-accumulated-heat/accumulator.coffee
@@ -53,9 +53,7 @@
             for j in [0..256]
                 energyIn = sc * input(lng(i), lat(j), time, light1, light2) * tao
                 data[i][j] = data[i][j] + energyIn
-        for i in [0..256]
-            for j in [0..256]
-                arr[j] = data[i][j] / lday
+                avg[i][j] = data[i][j] / lday

         avg


:construction: First test for transactions


fix snapping with multiple keys selected

--- src/scripts/graph/Keys.coffee
+++ src/scripts/graph/Keys.coffee
@@ -23,10 +23,11 @@

         currentDomainStart = self.timeline.x.domain()[0]
         mouse = d3.mouse(this)
+        old_time = d.time
         dx = self.timeline.x.invert(mouse[0])
         dx = dx.getTime()
-        time_offset = dx / 1000 - currentDomainStart / 1000
-        dx = d.time + time_offset
+        dx = dx / 1000 - currentDomainStart / 1000
+        dx = d.time + dx

         timeMatch = false
         if sourceEvent.shiftKey
@@ -35,6 +36,7 @@
           timeMatch = dx

         d.time = timeMatch
+        time_offset = d.time - old_time

         selection = self.timeline.selectionManager.getSelection()
         selection = _.filter(selection, (item) => item.isEqualNode(this) == false)


Sort inline comments by date

Sort inline comments by date

--- app/assets/javascripts/1-components/diff_view.js.coffee
+++ app/assets/javascripts/1-components/diff_view.js.coffee
@@ -131,7 +131,7 @@
         else
           Line key: j, lineNo: currentLineNo, content: s, highlight: side == 'b' && props.highlightLine == currentLineNo,
             if (currentInlineComments = inlineCommentBySideLine[side][currentLineNo])
-              currentInlineComments.map (comment) ->
+              _(currentInlineComments).sortBy((c) -> c.date).map (comment) ->
                 InlineComment key: comment.id, comment: comment, owner: props.owner

     if segments.length == 1 && segments[0].class == 'equal' && !@state.wholeDiffExpanded


Make all dialogs draggable.

Make all dialogs draggable.

--- app/assets/javascripts/alchemy/alchemy.dialog.js.coffee
+++ app/assets/javascripts/alchemy/alchemy.dialog.js.coffee
@@ -34,11 +34,10 @@
     window.requestAnimationFrame =>
       @dialog_container.addClass('open')
       @overlay.addClass('open') if @overlay?
-    unless @options.modal
-      @dialog.draggable
-        iframeFix: true
-        handle: '.alchemy-dialog-title'
-        containment: 'parent'
+    @dialog.draggable
+      iframeFix: true
+      handle: '.alchemy-dialog-title'
+      containment: 'parent'
     Alchemy.currentDialogs.push(this)
     @load()
     true


Hide passcode if empty

Hide passcode if empty

I tried showing "No passcode", but it looked confusing.

--- app/assets/javascripts/components/overview/details.cjsx
+++ app/assets/javascripts/components/overview/details.cjsx
@@ -48,7 +48,7 @@
         <fieldset>
           <TextInput
             onChange={@updateDetails}
-            value={@props.course.passcode}
+            value={display_code}
             value_key='passcode'
             editable={@props.editable}
             type='text'


Hide sidebar also when pressing enter in multiword view

--- app/assets/javascripts/rglossa/views/corpus_view.coffee
+++ app/assets/javascripts/rglossa/views/corpus_view.coffee
@@ -8,6 +8,8 @@
   didInsertElement: ->
     @determineHideSidebarSelector()
     @$().on('click', @hideSidebarSelector, @hideSidebar)
+    @$().on 'keyup', (e) =>
+      @hideSidebar() if e.keyCode is 13 and $('body').width() <= @maxAutoHideSidebarWidth

     if @get('controller.metadataCategories.length')
       @$().on('click', '#show-criteria-button, #new-search-button', @showSidebar)


remove keyboard drag/drop in outcomes page

fixes CNVS-26060

Test plan:
1.  Go to account or course outcomes page with multiple
    levels of outcomes defined
Using keyboard navigation:
2.  Navigate to an outcome
3.  Verfify that space selects the outcome (and does not
    start a drag/copy)
4.  Move to an outcome group in directory view
5.  Verify that space bar selects the outcome group
    (and does not complete a drag/copy)

Change-Id: I468d2469807fcc7b44764287a86a27e620dd1377
Reviewed-on: https://gerrit.instructure.com/70751
Tested-by: Jenkins
Reviewed-by: Matt Berns <e53c8988cd428dde240324ce2797c8eb7073560f@instructure.com>
QA-Review: Deepeeca Soundarrajan <5bcd4b623f00b7fc2942cd1c65c245b30a48a61f@instructure.com>
Product-Review: Nathan Rogowski <2e8aa918660411855c6d44d5bb2da677aa033255@instructure.com>

--- app/coffeescripts/views/outcomes/OutcomeIconBase.coffee
+++ app/coffeescripts/views/outcomes/OutcomeIconBase.coffee
@@ -40,9 +40,8 @@
       'focus':   'onFocus'

     keyCodes:
-      13: 'Enter'
-      27: 'Escape'
-      32: 'Space'
+      13: 'Action'
+      32: 'Action'
       37: 'LeftArrow'
       38: 'UpArrow'
       39: 'RightArrow'
@@ -111,58 +110,8 @@
     # Internal: Trigger a select when enter key is pressed.
     #
     # Returns nothing.
-    onEnterKey: (e, $target) ->
+    onActionKey: (e, $target) ->
       if $target.hasClass('outcome-group') then @onRightArrowKey(e, $target) else @triggerSelect()
-
-    # Internal: Store a group or outcome in another group.
-    #
-    # Returns nothing.
-    onDrop: (dragObject, $destination) ->
-      # TODO: reduce duplication b/w this and OutcomesDirectoryView.initDroppable
-      $target         = dragObject.$li
-      model           = dragObject.model
-      destinationView = $destination.data('view')
-      originalView    = dragObject.parent
-      if destinationView?
-        model.collection.remove(model)
-        if $target.hasClass('outcome-link') then destinationView.outcomes.add(model) else destinationView.groups.add(model)
-        model.trigger 'select'
-        dfd = destinationView.moveModelHere(model)
-      else
-        destinationView = originalView
-      return unless dfd
-      dfd.done ->
-        $('.wrapper [data-id=' + $target.data('id') + ']').attr('tabindex', 0).attr('aria-grabbed', false).focus()
-        $destination.parents('.wrapper:first').data('drag', null)
-
-    # Internal: Start drag or initiate drop.
-    #
-    # Returns nothing.
-    onSpaceKey: (e, $target) ->
-      $sidebar = $target.parents('.wrapper:first')
-      if dragObject = $sidebar.data('drag')
-        # drop
-        $target.after(dragObject.$li)
-        @onDrop(dragObject, $target.parent())
-      else
-        # drag
-        $target.attr('aria-grabbed', true)
-        dragObject =
-          $li: $target,
-          model: $target.data('view').model
-          parent: $target.parent().data('view')
-        $sidebar.data('drag', dragObject)
-        $target.blur()
-        $target.focus()
-
-    # Internal: Cancel a drag and drop action.
-    #
-    # Returns nothing.
-    onEscapeKey: (e, $target) ->
-      $sidebar = $target.parents('.wrapper:first')
-      return unless dataObject = $sidebar.data('drag')
-      dataObject.$li.data('parent', null).attr('aria-grabbed', false)
-      $sidebar.data('drag', null);

     # Internal: Update tabindex on $el and its siblings.
     #


integrating mongoskin

integrating mongoskin

--- routes/pages.coffee
+++ routes/pages.coffee
@@ -10,13 +10,10 @@
   connection_string = process.env.MONGOHQ_URL
 else
   connection_string = "mongodb://localhost:27017/nodelove"
-  db = new mongo.Db("nodelove", new mongo.Server("localhost", 27017,
-    auto_reconnect: true
-  ),
-    safe: true
-  )

-db = mongo.db(connection_string + "?auto_reconnect");
+db = mongo.db(connection_string + "?auto_reconnect",
+  safe: false
+)

 db.open (err, db) ->
   unless err


feat(routes/users.coffee): 修复人员删除方法

feat(routes/users.coffee): 修复人员删除方法

--- routes/users.coffee
+++ routes/users.coffee
@@ -92,7 +92,7 @@
       res.redirect('back')

 router.get '/delete/:id', ensure_login.ensureLoggedIn(), (req, res) ->
-  db.collection('users').removeById req.params.id, (err, r) ->
+  skin_db.collection('users').removeById req.params.id, (err, r) ->
     if r == 1
       req.flash('success', '人员删除成功')
       res.redirect('back')


Updated rating colors description

Updated rating colors description

--- server/materials/data/level_about.coffee
+++ server/materials/data/level_about.coffee
@@ -909,15 +909,15 @@

В ряде сводных таблиц сначала указываются школьники, активность которых больше 0.1, и только потом все остальные.

Цвет

-
Имена школьников в таблицах рисуются цветом, определяемым их рейтингом и активностью. А именно, активность определяет яркость цвета (от почти черного до насыщенного), а рейтинг определяет оттенок (от фиолетового через все цвета радуги до красного). Например, школьник с рейтингом 1 и активностью 10 будет иметь ярко-фиолетовый цвет, школьник с рейтингом 1 и активностью 0.1 будет иметь темно-фиолетовый цвет, школьник с рейтингом примерно 1500 и активностью 10 будет иметь ярко-зеленый цвет, а с активностью 0.1 — темно-зеленый цвет; красный цвет соответствует рейтингу примерно 160000.

+
Имена школьников в таблицах рисуются цветом, определяемым их рейтингом и активностью. А именно, активность определяет яркость цвета (от почти черного до насыщенного), а рейтинг определяет оттенок (от фиолетового через все цвета радуги до красного). Например, школьник с рейтингом 1 и активностью 10 будет иметь ярко-фиолетовый цвет, школьник с рейтингом 1 и активностью 0.1 будет иметь темно-фиолетовый цвет, школьник с рейтингом примерно 100000 и активностью 10 будет иметь ярко-зеленый цвет, а с активностью 0.1 — темно-зеленый цвет; красный цвет соответствует рейтингу 4500000.

Конкретная формула: в модели HSV цвет участника имеет следующие компоненты:

-        $h = 11/12 \cdot (1 - log(r+1) / log(R + 1))$

-        $v = 0.3 + 0.7 \cdot log(a+1) / log(A + 1)$

+        $h = k\cdot \log(r+r_0) + b$

+        $v = 0.3 + 0.7 \cdot \log(a+1) / \log(A + 1)$

         $s = 1$

-
здесь $r$ и $a$ — рейтинг и активность, $R$ — "максимальный рейтинг" (те самые примерно 160000, точнее — рейтинг, который получит человек, на каждом уровне решивший по 10 задач, возможно, я буду подправлять константу в будущем), $A=7$.

-
-
Еще есть мелкие поправки на краях возможных интервалов значений. Код, кому интересно, здесь.

+
здесь $r$ и $a$ — рейтинг и активность, $A=7$, $r_0=200$, а константы $k$ и $b$ подбираются так, чтобы двух опорных точек (рейтинг 600 и рейтинг 4500000) получались правильные цвета (сине-фиолетовый и красный).

+
+
Еще есть мелкие поправки на краях возможных интервалов значений. Код здесь.

Параметры codeforces

Код


Correct urlencode ? for redirection from login when user isn t auth. #215

--- server/middlewares/authentication.coffee
+++ server/middlewares/authentication.coffee
@@ -33,6 +33,6 @@
         next()
     else
         url = "/login"
-        url += "?next=#{req.url}" unless req.url is '/'
+        url += "?next=#{req.url.replace "?", "%3F"}" unless req.url is '/'
         url += "&#{qs.stringify req.query}" if req.query.length
         res.redirect url


Emit this in every minutes.

Emit this in every minutes.

--- client/Framework/components/time/timeagoview.coffee
+++ client/Framework/components/time/timeagoview.coffee
@@ -2,7 +2,7 @@

   @registerStaticEmitter()

-  KD.utils.repeat 5000, => @emit "OneMinutePassed"
+  KD.utils.repeat 60000, => @emit "OneMinutePassed"

   constructor: (options = {}, data) ->


geoip/view: style of location is changed

--- client/account/lib/views/accounteditusername.coffee
+++ client/account/lib/views/accounteditusername.coffee
@@ -101,12 +101,22 @@
           name             : "confirmPassword"
           type             : "password"
           label            : 'Password (again)'
-        shareLocation      :
-          label            : 'Share my location while posting'
-          defaultValue     : whoami().shareLocation
-          itemClass        : KodingSwitch
-          cssClass         : 'tiny'
-          name             : 'shareLocation'
+        locationHeader     :
+          itemClass        : KDCustomHTMLView
+          partial          : 'LOCATION SERVICES'
+          cssClass         : 'AppModal-form-sectionHeader'
+        shareLocationLabel :
+          itemClass        : KDCustomHTMLView
+          partial          : 'Share my location while posting'
+          tagName          : 'ul'
+          cssClass         : 'AppModal--account-switchList'
+          name             : 'shareLocationLabel'
+          nextElement      :
+            shareLocation      :
+              defaultValue     : whoami().shareLocation
+              itemClass        : KodingSwitch
+              cssClass         : 'AppModal--account-switchList'
+              name             : 'shareLocation'
       buttons              :
         Save               :
           title            : 'Save Changes'


ShortcutsView: Use uppercase letters and remove broken key bindings.

--- client/ide/views/shortcutsview/shortcutsview.coffee
+++ client/ide/views/shortcutsview/shortcutsview.coffee
@@ -20,33 +20,33 @@

   getShortcuts: ->
     'Workspace Shortcuts':
-      'Ctrl-Alt-v'   : 'split vertically'
-      'Ctrl-Alt-h'   : 'split horizontally'
-      'Ctrl-Alt-m'   : 'merge splitview'
-      'Ctrl-Alt-n'   : 'create new file'
-      'Ctrl-Alt-c'   : 'collapse sidebar'
-      'Ctrl-Alt-e'   : 'expand sidebar'
-      'Ctrl-Alt-['   : 'go to left tab'
-      'Ctrl-Alt-]'   : 'go to right tab'
-      'Ctrl-Alt-1'   : 'go to tab number'
-      'Ctrl-Alt-2'   : 'go to tab number'
-      'Ctrl-Alt-3'   : 'go to tab number'
-      'Ctrl-Alt-4'   : 'go to tab number'
-      'Ctrl-Alt-5'   : 'go to tab number'
-      'Ctrl-Alt-6'   : 'go to tab number'
-      'Ctrl-Alt-7'   : 'go to tab number'
-      'Ctrl-Alt-8'   : 'go to tab number'
-      'Ctrl-Alt-9'   : 'go to tab number'
+      'Ctrl-Alt-V'   : 'Split vertically'
+      'Ctrl-Alt-H'   : 'Split horizontally'
+      'Ctrl-Alt-M'   : 'Merge splitview'
+      'Ctrl-Alt-N'   : 'Create new file'
+      'Ctrl-Alt-C'   : 'Collapse sidebar'
+      'Ctrl-Alt-E'   : 'Expand sidebar'
+      'Ctrl-Alt-['   : 'Go to left tab'
+      'Ctrl-Alt-]'   : 'Go to right tab'
+      'Ctrl-Alt-1'   : 'Go to tab number'
+      'Ctrl-Alt-2'   : 'Go to tab number'
+      'Ctrl-Alt-3'   : 'Go to tab number'
+      'Ctrl-Alt-4'   : 'Go to tab number'
+      'Ctrl-Alt-5'   : 'Go to tab number'
+      'Ctrl-Alt-6'   : 'Go to tab number'
+      'Ctrl-Alt-7'   : 'Go to tab number'
+      'Ctrl-Alt-8'   : 'Go to tab number'
+      'Ctrl-Alt-9'   : 'Go to tab number'

     'Editor Shortcuts':
-      'Ctrl-S'       : 'save'
-      'Ctrl-Shift-S' : 'saveAs'
-      'Ctrl-F'       : 'find'
-      'Ctrl-Shift-F' : 'replace'
-      'Ctrl-Shift-P' : 'preview'
-      'Ctrl-Enter'   : 'fullscreen'
-      'Ctrl-G'       : 'gotoLine'
-      'Ctrl-L'       : 'gotoLine'
-      'Ctrl-Alt-S'   : 'saveAll'
-      'Ctrl-W'       : 'closeTab'
-      'Ctrl-,'       : 'settings'
+      'Ctrl-S'       : 'Save'
+      'Ctrl-F'       : 'Find'
+      'Ctrl-Shift-F' : 'Find and Replace'
+      'Ctrl-Enter'   : 'Fullscreen'
+      'Ctrl-G'       : 'Go to Line'
+      'Ctrl-L'       : 'Go to Line'
+      # 'Ctrl-Shift-S' : 'saveAs'
+      # 'Ctrl-Shift-P' : 'preview'
+      # 'Ctrl-Alt-S'   : 'saveAll'
+      # 'Ctrl-W'       : 'closeTab'
+      # 'Ctrl-,'       : 'settings'


improve error management of init phase

improve error management of init phase

--- init.coffee
+++ init.coffee
@@ -8,10 +8,13 @@
 total_files = 0
 thumb_files = 0

+
 module.exports.onThumbCreation = () ->
     return [thumb_files isnt total_files, (thumb_files / total_files) * 100]

+
 convertImage = (cb) ->
+
     convert = (doc, callback) ->
         if doc._attachments?
             try
@@ -24,25 +27,39 @@
                 callback()
         else
             callback()
+
     Photo.all (err, docs) ->
-        async.eachSeries(docs, convert, cb)
+        if err
+            cb err
+        else
+            async.eachSeries docs, convert, cb
+

 createThumb = (socket, cb) ->
+
     # Recover all file without thumb
     File.withoutThumb (err, files) ->
-        total_files = files.length
-        # Create thumb and check progress
-        async.eachSeries files, (file, callback) ->
-            thumb file, () ->
-                thumb_files += 1
-                percent = Math.floor((thumb_files / total_files) * 100)
-                # Emit thumb creation progress
-                socket.emit 'progress', {"percent": percent}
-                callback()
-        , cb
+        if err
+            cb err
+
+        else if files?
+            total_files = files.length
+            # Create thumb and check progress
+            async.eachSeries files, (file, callback) ->
+                thumb file, () ->
+                    thumb_files += 1
+                    percent = Math.floor((thumb_files / total_files) * 100)
+                    # Emit thumb creation progress
+                    socket.emit 'progress', {"percent": percent}
+                    callback()
+            , cb
+
+        else
+            cb()
+

 # Create all requests and upload directory
-module.exports.convert = (socket, done=->null) ->
+module.exports.convert = (socket, done= -> null) ->
     #convertImage (err) ->
     onThumbCreation = true
     createThumb socket, ->


Remove unused function

Remove unused function

--- resources/assets/coffee/osu_common.coffee
+++ resources/assets/coffee/osu_common.coffee
@@ -6,10 +6,6 @@

 window.osu =
   isIos: /iPad|iPhone|iPod/.test(navigator.platform)
-
-  currentUserIsFriendsWith: (user_id) ->
-    _.find currentUser.friends, target_id: user_id
-

   groupColour: (group) ->
     '--group-colour': group?.colour ? 'initial'


prepend a "fake" activity when you make a new challenge

--- core/app/backbone/views/react_feed_selection.coffee
+++ core/app/backbone/views/react_feed_selection.coffee
@@ -23,6 +23,14 @@
       displaystring: @refs.challengeDescription.getDOMNode().value
       site_title: @refs.challengeName.getDOMNode().value
       site_url: 'kennisland_challenge'
+
+    newActivity =
+      new Activity
+        action: 'created_fact'
+        fact: fact.toJSON()
+        user: currentSession.user().toJSON()
+
+    @state.feeds.discussions.unshift newActivity

     fact.save {},
       success: =>


Use defaultClickHandler to navigate to subChannel

--- core/app/backbone/views/subchannel_item_view.coffee
+++ core/app/backbone/views/subchannel_item_view.coffee
@@ -17,11 +17,8 @@
     @$('i.close').hide() unless currentChannel.user().get('id') == currentUser.get('id')

   clickHandler: (e) ->
-    return  if e.metaKey or e.ctrlKey or e.altKey
     mp_track "Channel: Click on subchannel",
       channel_id: currentChannel.id
       subchannel_id: @model.id

-    Backbone.history.navigate @model.get("created_by").username + "/channels/" + @model.id, true
-    e.preventDefault()
-    false
+    @defaultClickHandler e


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com


Clean up audio_async_spec.coffee

Clean up audio_async_spec.coffee


Clear search input on search close.

Clear search input on search close.

--- src/views/search-input.coffee
+++ src/views/search-input.coffee
@@ -18,6 +18,9 @@
         template: 'navigation-search'
         initialize: (@model, @searchResults) ->
             @listenTo @searchResults, 'ready', @adaptToQuery
+            @listenTo @searchResults, 'reset', =>
+                if @searchResults.isEmpty()
+                    @setInputText ''
         adaptToQuery: (model, value, opts) ->
             $container = @$el.find('.action-button')
             $icon = $container.find('span')


use build-in ember utils

use build-in ember utils

--- client/app/components/pagination_links_component.coffee
+++ client/app/components/pagination_links_component.coffee
@@ -1,7 +1,5 @@
 module.exports = Ember.Component.extend
   classNames: ['pagination']
-  classNameBindings: ['kHide']
-  #showPaginator: yes
   pages: (->
     needAddStart = 0
     needAddEnd = 0
@@ -48,8 +46,8 @@
     pagesArray
   ).property "pageSize", "allCount", 'curPageNum'

-  kHide: (->
+  isVisible: (->
     pages = @get 'pages'
-    pages.length <= 1
+    pages.length > 1
   ).property 'pages'


stack-editor: add stack script search view for admins

--- client/stack-editor/lib/editor/stacktemplateview.coffee
+++ client/stack-editor/lib/editor/stacktemplateview.coffee
@@ -1,8 +1,9 @@
-kd                      = require 'kd'
-KDButtonView            = kd.ButtonView
-Encoder                 = require 'htmlencode'
-curryIn                 = require 'app/util/curryIn'
+kd = require 'kd'
+KDButtonView = kd.ButtonView
+Encoder = require 'htmlencode'
+curryIn = require 'app/util/curryIn'
 StackTemplateEditorView = require './stacktemplateeditorview'
+StackScriptSearchView = require './stackscriptsearchview'

 module.exports = class StackTemplateView extends kd.View
@@ -28,6 +29,9 @@
       content = null

     delegate = @getDelegate()
+    @searhText = null
+    if @canUpdate
+      @addSubView new StackScriptSearchView

     @addSubView @editorView = new StackTemplateEditorView {
       delegate: this, content, contentType, showHelpContent
@@ -73,3 +77,4 @@
   setReadOnly: ->
     @setClass 'readonly'
     @editorView.aceView.ace.editor.setReadOnly yes
+


fix for param-selector

fix for param-selector

--- src/components/widgets/accounts-assets-liability-summary/accounts-assets-liability-summary.directive.coffee
+++ src/components/widgets/accounts-assets-liability-summary/accounts-assets-liability-summary.directive.coffee
@@ -32,7 +32,7 @@

     if !$scope.selectedAccountsOption
       $scope.selectedAccountsOption = _.find($scope.accountsOptions, {
-        value: w.metadata.classification
+        value: w.metadata.classification || 'ASSET'
       });

     if w.metadata.organization_ids.length > 1


Fix being too clever

Fix being too clever

--- app/core/initialize.coffee
+++ app/core/initialize.coffee
@@ -7,7 +7,8 @@
     unless unwantedEventsRegex.test(channel)
       try
         filteredStack = (new Error()).stack.split("\n")[depth].trim().replace('.prototype', '')
-        unless unwantedStackRegex.test(filteredStack.substr(0, filteredStack.indexOf('@webpack-internal')))
+        filteredStack = filteredStack.substr(0, filteredStack.indexOf('@webpack-internal'))
+        unless unwantedStackRegex.test(filteredStack)
           console.log(">>> #{filteredStack} -> publishing #{channel}")
         else if depth < maxDepth
           attemptStackLog(channel, arg, depth + 1) # Down the rabbit hole...


ログには出てるのにメッセージ来ねーなと思ったらコメントアウトされてるじゃねーか。

--- scripts/cron.coffee
+++ scripts/cron.coffee
@@ -69,7 +69,7 @@
                     md = moment(result).format('M月D日(ddd)')
                     hm = moment(result).format('HH:mm')
                     message = '明日 ' + md + ' は Bandroid の開催日です！\n開始予定時刻は ' + hm + ' です。'
-                    # robot.send {room: 'test'}, message
+                    robot.send {room: 'test'}, message
                     robot.logger.debug 'send message: ' + message
             )
     )


Update to docs to support docs type and version separately.

Added support for API versions (3, 4.*)
This was brought up in issue #24

Limiting the response for No result, to avoid a possibly large query response

--- scripts/docs.coffee
+++ scripts/docs.coffee
@@ -13,20 +13,29 @@
 cheerio   = require 'cheerio'
 htmlStrip = require 'htmlstrip-native'

+TARGET_VERSION = '4.2'
 SEARCH_URL = 'https://www.google.com/search'
 USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36'
 #Rommie=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17

 module.exports = (robot) ->
-  getQueryUrl = (version, query) ->
-    if version.match(/^3(.*)/i)
-      "site:three.laravel.com/docs #{query}"
-    else if version == 'api'
-      "site:laravel.com/api/4.1 #{query}"
-    else if version == 'php'
+  getQueryUrl = (doctype, version, query) ->
+    version = 3 if version?.match /^3(.*)/i
+
+    if doctype == 'api'
+      if version == 3
+        "site:l3.shihan.me/api #{query}"
+      else if version?
+        "site:laravel.com/api/#{version} #{query}"
+      else
+        "site:laravel.com/api/#{TARGET_VERSION} #{query}"
+    else if doctype == 'php'
       "site:php.net/manual/en #{query}"
     else
-      "site:laravel.com/docs #{query}"
+      if version == 3
+        "site:three.laravel.com/docs #{query}"
+      else
+        "site:laravel.com/docs #{query}"

   fetchResult = (query, callback) ->
     robot.http(SEARCH_URL)
@@ -39,28 +48,19 @@
         url = result.find('.st .f a').attr('href') ? result.find('h3.r a').attr('href')
         callback url if callback

-  robot.hear /(([^:,\s!]+)[:,\s]+)?!docs\s?([0-9.]+|api|dev|php)?\s(.*)/i, (msg) ->
+  robot.hear /(([^:,\s!]+)[:,\s]+)?!docs\s?(api|php)?\s?([0-9.]+)?\s?(.*)/i, (msg) ->
     user = msg.match[2]
-    version = msg.match[3]
-    query = msg.match[4]
+    doctype = msg.match[3]
+    version  = msg.match[4]
+    query = msg.match[5]

-    # quick and dirty urlify version string
-    # (beware if we get into 2 digit minor vers)
-    if (version != 'dev' or version != 'api')
-      if !version?
-        version = ''
-      else if version.length > 1
-        version = version.replace(/[\.]/g, "-").substr(0, 3)
-      else if version == '4'
-        version = ''
-
-    fetchResult getQueryUrl(version, query), (url) ->
-      return msg.send "No results for \"#{query}\"" unless url
+    fetchResult getQueryUrl(doctype, version, query), (url) ->
+      return msg.send "No results for \"#{query.substr(0,30)}\"" unless url

       response = url
       response = "#{user}: #{response}" if user

-      if version == 'php' and /function/.test url
+      if doctype == 'php' and /function/.test url
         robot.http(url).get() (err, res, body) ->
           $ = cheerio.load body
           methodSigContent = htmlStrip.html_strip $('.methodsynopsis').html(), compact_whitespace : true


Quick formatting fix

Quick formatting fix

--- scripts/ilvl.coffee
+++ scripts/ilvl.coffee
@@ -25,24 +25,24 @@
     deferred = Q.defer()

     msg
-    .http("#{baseURL}guild/#{realm}/#{guild}")
-    .query
-      fields: "members"
-      locale: locale
-      apikey: key
-    .get() (err, res, body) ->
-      if err
-        deferred.reject err
-      else
-        resp = JSON.parse body
-        Q.all((getILvl msg, member.character.name for member in resp.members))
-          .then (data) ->
-            deferred.resolve data
+      .http("#{baseURL}guild/#{realm}/#{guild}")
+      .query
+        fields: "members"
+        locale: locale
+        apikey: key
+      .get() (err, res, body) ->
+        if err
+          deferred.reject err
+        else
+          resp = JSON.parse body
+          Q.all((getIlvl msg, member.character.name for member in resp.members))
+            .then (data) ->
+              deferred.resolve data

     return deferred.promise

   # HTTP GET item level of a character
-  getILvl = (msg, name) ->
+  getIlvl = (msg, name) ->
     deferred = Q.defer()

     msg


Fix old party.editRoute#auth links

Fix old party.editRoute#auth links

--- web/party/profile.coffee
+++ web/party/profile.coffee
@@ -58,7 +58,7 @@
         if $scope.editable
           $scope.selected.editAccess(@party)
         else if t
-          $location.url(party.editRoute(t)+'#auth-'+@party.id)
+          $location.url(party.editRoute(t, @party.id))

     class Volume extends Item
       constructor: (@volume) ->
@@ -130,7 +130,7 @@
       unless a.member || a.site
         messages.add
           type: 'yellow',
-          body: $sce.trustAsHtml('' + constants.message('auth.notice.pending', {sce:$sce.HTML}, a.party.name) + ' Manage.')
+          body: $sce.trustAsHtml('' + constants.message('auth.notice.pending', {sce:$sce.HTML}, a.party.name) + ' Manage.')
     parties.collaborators = (Party.all[pi] for pi of collaborators)

     stringSort = (a,b) -> +(a > b) || +(a == b) - 1


first time click selects the checkbox -- in progress

--- web/volume/design.coffee
+++ web/volume/design.coffee
@@ -10,8 +10,15 @@
       volume = $scope.volume
       form = $scope.volumeDesign

+      clickOn = 0;
       $element.on 'click', (e) ->
-        angular.element(e.target).not('input').closest('li.clickable').find('input').trigger 'click'
+        if clickOn == 0
+          angular.element(e.target).not('input').closest('li.clickable').find('input').trigger 'click'
+          angular.element(e.target).not('input').closest('li.clickable').find('input').trigger 'click'
+          clickOn = 1
+          console.log(clickOn)
+        else
+          angular.element(e.target).not('input').closest('li.clickable').find('input').trigger 'click'
         return

       $scope.select = (c) ->


blind fix for ⍞ input

blind fix for ⍞ input

--- client/ide.coffee
+++ client/ide.coffee
@@ -85,6 +85,7 @@
       NotAtInputPrompt: => @wins[0].prompt 0; return
       AtInputPrompt: ({why}) =>
         if @pending.length then @emit 'Execute', trace: 0, text: @pending.shift() + '\n' else @wins[0].prompt why
+        if why == 4 then @wins[0].focus() # ⍞ input
         return
       HadError: => @pending.splice 0, @pending.length; return
       FocusWindow: ({win}) => $("#wintab#{win} a").click(); @wins[win]?.focus(); return


Clearer error when descriptor is null

Clearer error when descriptor is null


Remove 90 degree limit from fan tool

Remove 90 degree limit from fan tool

--- app/models/fan_mark.coffee
+++ app/models/fan_mark.coffee
@@ -18,7 +18,7 @@

   'set distance': (value) -> Math.max value, 10

-  'set spread': (value) -> Math.min 90, Math.max 1, value
+  'set spread': (value) -> Math.min 179.99, Math.max 1, value

   toJSON: ->
     {@type, @source, @distance, @angle, @spread}


eliminate a variable that isn't used.

eliminate a variable that isn't used.

--- cf/spell.coffee
+++ cf/spell.coffee
@@ -1,7 +1,7 @@
 $ ->

   @current = ""
-  @context = this
+
   $("#question, #answer").hide()
   words = $.getJSON("spellings.json")
   $.when(words).done ((d)->


Remove old file

Remove old file

--- views/akashic-resource-table.cjsx
+++ views/akashic-resource-table.cjsx
@@ -1,41 +0,0 @@
-{React, ReactBootstrap, jQuery} = window
-{Grid, Col, Table} = ReactBootstrap
-
-AkashicResourceCheckboxArea = require './akashic-resource-checkbox-area'
-AkashicResourceTableArea = require './akashic-resource-table-area'
-
-dateToDateString = (datetime)->
-  date = new Date(datetime)
-  "#{date.getFullYear()}#{date.getMonth() + 1}#{date.getDate()}"
-AkashicResourceTable = React.createClass
-  getInitialState: ->
-    rowChooseChecked: [true, true, true, true, true, true, true, true, true, true, true, true,
-                      true, true]
-  rowChooseChecked: [true, true, true, true, true, true, true, true, true, true, true, true,
-                      true, true]
-  dataLength: 0
-  componentWillMount: ->
-    @rowChooseChecked = JSON.parse config.get "plugin.Akashic.resource.table.checkbox", JSON.stringify @state.rowChooseChecked
-    rowChooseChecked = JSON.parse JSON.stringify @rowChooseChecked
-    @setState
-      rowChooseChecked: rowChooseChecked
-  filterRules: (checked) ->
-    @setState
-      rowChooseChecked: checked
-  shouldComponentUpdate: (nextProps, nextState)->
-    refreshFlag = false
-    for item, i in @rowChooseChecked
-      if item isnt nextState.rowChooseChecked[i]
-        @rowChooseChecked[i] = nextState.rowChooseChecked[i]
-        refreshFlag = true
-    if nextProps.data.length isnt @dataLength
-      refreshFlag = true
-      @dataLength = nextProps.data.length
-    refreshFlag
-  render: ->
-    <div>
-      <AkashicResourceCheckboxArea tableTab={@props.tableTab} filterRules={@filterRules} rowChooseChecked={@state.rowChooseChecked}/>
-      <AkashicResourceTableArea tableTab={@props.tableTab} data={@props.data} rowChooseChecked={@state.rowChooseChecked} />
-    </div>
-
-module.exports = AkashicResourceTable


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera_fade.coffee
+++ src/camera_fade.coffee
@@ -17,7 +17,7 @@
     color: 'black'

   fadeOutDefaults =
-    color: 'transparen'
+    color: 'transparent'

   configureFade = (duration, color, alpha) ->
     I.flashDuration = duration