update

update

--- app/locale/zh-HANS.coffee
+++ app/locale/zh-HANS.coffee
@@ -1,34 +1,34 @@
 module.exports = nativeDescription: "简体中文", englishDescription: "Chinese (Simplified)", translation:
-
-#  ozaria_home:
-#    subtitle: "Computer Science that Captivates"
-#    summary: "Ozaria is a computer science program, an adventure game, and a fantasy story where students master the lost magic of coding to save their world."
-#    value_prop1_h1: "Epic Story. Immersive Gameplay."
-#    value_prop1_h2: "Inspire a deeper connection to learning"
-#    value_prop1_p: "In Ozaria, students find themselves embedded in a new world where they master core computer science concepts to progress within the game. The unfolding narrative creates a powerful student-centered learning experience, with each student’s investment in Ozaria’s story paralleling the investment they are making in their own learning journey."
-#    value_prop2_h1: "Discover the Hero within Every Student"
-#    value_prop2_h2: "Build real skills through play"
-#    value_prop2_p: "Concepts and skills are introduced via a thoughtfully-designed content progression that includes game levels, instructional character dialogue, cutscenes, and more. Students learn to type Python or JavaScript, problem-solve using computational thinking, demonstrate understanding through formative assessments, and apply what they learn by making their own projects."
-#    value_prop3_h1: "Start Your Journey For Free"
-#    value_prop3_p: "Teach through adventure with free content covering introductory computer science concepts, plus access to implementation guides and lesson plans."
-#    projects_inspire_heading: "Projects that Inspire. Resources that Empower."
-#    student_creativity: "Unleash Student Creativity"
-#    student_creativity_paragraph: "At the end of each unit, students apply what they've learned by creating projects, from games to choose-your-own adventure stories and more. Built with scaffolded goals, yet allowing for limitless ideation, students build a shareable and playable portfolio of work that showcases their creative identity."
-#    teach_with_support: "Teach with Support"
-#    teach_with_support_paragraph: "Ozaria is built for educators. Each unit throughout the curriculum has a lesson plan that outlines learning objectives, common student misconceptions, key terms, and CSTA standards. In addition, a comprehensive teacher dashboard helps teachers to track student progress and check student code."
-#    request_demo: "Request a Demo"
-#    im_an_educator: "I'm an Educator"
-#    im_a_student: "I'm a Student"
-#    global_title: "Join Our Global Community of Learners and Educators"
-#    global_subtitle1: "Learners"
-#    global_subtitle2: "Lines of Code"
-#    global_subtitle3: "Teachers"
-#    global_subtitle4: "Countries"
-#    sign_up: "Sign Up"
+  ozaria_home:
+    subtitle: "引人入胜的计算机科学教程"
+    summary: "Ozaria（“奥佳睿”）既是计算机科学程序，扣人心弦的冒险游戏，也是一个让学生们掌握计算机代码魔法来拯救世界的科幻故事。"
+    value_prop1_h1: "史诗故事，沉浸式体验"
+    value_prop1_h2: "Inspire a deeper connection to learning"
+    value_prop1_p: "在奥佳睿，学生们身处史诗故事的中心，他们必须通过掌握计算思维来晋级。逐渐展开的情节打造出以学生为中心的学习体验，基于每个学生对奥佳睿的投入程度。"
+    value_prop2_h1: "Discover the Hero within Every Student"
+    value_prop2_h2: "Build real skills through play"
+    value_prop2_p: "计算机科学概念和技能通过富有吸引力的内容切入，包括游戏关卡、教学角色对话、过渡动画等。学生学习键入 Python 或 JavaScript 真实代码，运用计算思维解决问题，通过结构性教学评估证验证知识理解，并制作自己的项目来应用所学知识。"
+    value_prop3_h1: "免费开启你的编程之旅"
+    value_prop3_p: "通过冒险故事的进行开展授课，提供涵盖计算机科学入门概念的免费内容，以及获得课程指南和课程计划的渠道。"
+    projects_inspire_heading: "Projects that Inspire. Resources that Empower."
+    student_creativity: "Unleash Student Creativity"
+    student_creativity_paragraph: "在每个单元最后，学生将运用所学知识创建自己的项目，包括选择你自己的冒险故事到游戏设计中来。建立在明确目标下，但可以有无限构想的内容形式，创建共享和可玩的作品集，展示了学生们无限的创造力。"
+    teach_with_support: "Teach with Support"
+    teach_with_support_paragraph: "Ozaria（“奥佳睿”）专为教育工作者而建。 整个课程中的每个单元都有一个课程计划，概述学习目标，常见学生误区，关键术语和CSTA标准。 此外，完善的教学管理后台可以帮助教师跟踪学生的进度并检查学生的代码。"
+    request_demo: "Request a Demo"
+    im_an_educator: "我是老师"
+    im_a_student: "我是学生"
+    global_title: "Join Our Global Community of Learners and Educators"
+    global_subtitle1: "学习者"
+    global_subtitle2: "行代码"
+    global_subtitle3: "老师"
+    global_subtitle4: "国家"
+    sign_up: "注册"
+

   new_home:
-#    title: "Ozaria - Computer science that captivates"
-#    meta_description: "Ozaria is a computer science program, an adventure game, and a fantasy story where students master the lost magic of coding to save their world."
+    title: "Ozaria - 引人入胜的计算机科学教程"
+    meta_description: "Ozaria（“奥佳睿”）既是计算机科学程序，扣人心弦的冒险游戏，也是一个让学生们掌握计算机代码魔法来拯救世界的科幻故事。"
     built_for_teachers_title: "一个以教师为中心的课程体系"
     built_for_teachers_blurb: "教孩子们写代码往往会觉得无从下手。 CodeCombat 旨在帮助所有的教育工作者传授学生学习和掌握当下最流行的两种计算机语言，JavaScript 和 Python。整个体系包含六门计算机科学课程，以及通过基于项目的游戏开发和网页开发单元巩固学习，教会孩子们一步步从基本语法到高级递归前进！"
     built_for_teachers_subtitle1: "计算机科学"
@@ -175,8 +175,9 @@
     view_progress: "查看进度"
     go_to_courses: "进入我的课程"
     want_coco: "把 CodeCombat 带到您的学校？"
-#    educator: "Educator"
-#    student: "Student"
+    educator: "教师"
+    student: "学生"
+    go_to_my_dashboard: "进入我的课程"

   nav:
     educators: "教育者"
@@ -221,14 +222,14 @@
     resource_hub: "资源中心"
     apcsp: "AP计算机科学原理"
     parent: "家长参与"
-#    faq: "FAQ"
-#    return_coco: "Return to CodeCombat"
-#    classes: "Classes"
+    faq: "常见问题"
+    return_coco: "返回CodeCombat"
+    classes: "我的课程"

   modal:
     close: "关闭"
     okay: "是"
-#    cancel: "Cancel"
+    cancel: "取消"

   not_found:
     page_not_found: "找不到网页"
@@ -273,7 +274,7 @@
     achievements: "成就" # Tooltip on achievement list button from /play
     settings: "设置" # Tooltip on settings button from /play
     poll: "投票" # Tooltip on poll button from /play
-    next: "下一页" # Go from choose hero to choose inventory before playing a level
+    next: "下一步" # Go from choose hero to choose inventory before playing a level
     change_hero: "重新选择英雄" # Go back from choose inventory to choose hero
     change_hero_or_language: "切换英雄或者语言"
     buy_gems: "购买宝石"
@@ -295,9 +296,9 @@
     back_to_classroom: "返回教室"
     teacher_button: "带到学校"
     get_more_codecombat: "获取跟过CodeCombat游戏的信息"
-#    back_to_dashboard: "Back to Dashboard"
-#    back_to_ozaria: "Back to ozaria.com"
-#    customize_hero: "Customize Hero"
+    back_to_dashboard: "返回我的课程"
+    back_to_ozaria: "返回奥佳睿首页"
+    customize_hero: "英雄设置"

   code:
     if: "如果" # Keywords--these translations show up on hover, so please translate them all, even if it's kind of long. (In the code editor, they will still be in English.)
@@ -361,7 +362,7 @@
 #    auth_sign_up: "New to Ozaria? Create an Account"
     sign_up: "注册"
     email_or_username: "邮箱或用户名" # {change}
-#    or: "or"
+    or: "或"
     log_in: "登录"
 #    sign_in: "Sign In"
     logging_in: "正在登录"
@@ -449,7 +450,7 @@
     teacher_list_resource_hub_3: "关卡解决方案，和"
     teacher_list_resource_hub_4: "资源汇总"
     teacher_list_resource_hub_5: "课程指导，课程活动和更多信息！"
-    teacher_additional_questions: "如果需要额外帮助或遇到问题，请联系 bill@codecombat.com。"
+    teacher_additional_questions: "如果需要额外帮助或遇到问题，请联系 china@codecombat.com。"
     dont_use_our_email_silly: "请填写家长的邮箱地址。"
     want_codecombat_in_school: "想接着玩CodeCombat?"
     eu_confirmation: "我同意 CodeCombat 在美国的服务器上存储我的数据"
@@ -480,10 +481,10 @@
     back: "返回" # When used as an action verb, like "Navigate backward"
     coming_soon: "敬请期待！"
     continue: "继续" # When used as an action verb, like "Continue forward"
-    next: "下一个"
+    next: "下一步"
     default_code: "默认代码"
     loading: "读取中……"
-#    LOADING: "LOADING"
+    LOADING: "加载中"
     overview: "概览"
     processing: "进行中……"
     solution: "解法"
@@ -509,11 +510,11 @@
     submit_changes: "提交更新"
     save_changes: "保存更新"
     required_field: "必填" # {change}
-#    submit: "Submit"
-#    replay: "Replay"
-#    complete: "Complete"
-#    continue_editing: "Continue Editing"
-#    logout: "Logout"
+    submit: "提交"
+    replay: "重新开始"
+    complete: "完成"
+    continue_editing: "继续编辑"
+    logout: "退出登录"

   general:
     and: "与"
@@ -596,7 +597,7 @@

   play_level:
     back_to_map: "返回地图"
-    directions: "方向"
+    directions: "游戏指引"
     edit_level: "编辑关卡"
     keep_learning: "不断学习"
     explore_codecombat: "探索CodeCombat"
@@ -673,7 +674,7 @@
     tome_cast_button_run: "运行"
     tome_cast_button_running: "正在运行"
     tome_cast_button_ran: "运行过"
-#    tome_cast_button_update: "Update"
+    tome_cast_button_update: "更新"
     tome_submit_button: "提交"
     tome_reload_method: "恢复关卡初始代码"
     tome_available_spells: "可用的法术"
@@ -778,8 +779,8 @@
     concept_unlocked: "已解锁的概念"
     use_at_least_one_concept: "请使用以下至少一个概念： "
 #    command_bank: "Code Bank"
-#    learning_goals: "Learning Goals"
-#    start: "Start"
+    learning_goals: "学习目标"
+    start: "开始"
 #    vega_character: "Vega Character"
     click_to_continue: "点击继续"
     share_your_project: "分享你的项目"
@@ -804,8 +805,8 @@
     methods: "函数"
     events: "事件"
 #    handlers: "Handlers"
-#    properties: "Properties"
-#    snippets: "Snippets"
+    properties: "属性"
+    snippets: "字段"
     spawnable: "可生成物"
     html: "HTML"
     math: "数学"
@@ -836,7 +837,7 @@
     created_during_hoc: "在“编程一小时”中创建。"
     restart: "重新开始关卡"
     play: "开始关卡"
-    learn_about_ozaria: "Learn About Ozaria"
+    play_more_codecombat: "玩更多的 CodeCombat 关卡"
     default_student_instructions: "单击控制英雄，并取得胜利！"
     goal_survive: "生存。"
     goal_survive_time: "生存 __seconds__ 秒。"
@@ -963,7 +964,7 @@
     year_subscription: "年度订阅"
     year_price: "$__price__/年"
     support_part1: "付款时需要帮助? Email" # {change}
-    support_part2: "bill@codecombat.com"
+    support_part2: "china@codecombat.com"

   announcement:
     now_available: "现在订阅者可以获得更多内容"
@@ -1132,7 +1133,7 @@
     learn_more: "了解更多"
     main_title: "学习编程需要动手写大量代码"
     main_description: "CodeCombat让你带着微笑学习"
-    mission_link: "任务"
+    mission_link: "愿景"
     team_link: "团队"
     story_link: "历程"
     press_link: "联系方式"
@@ -1142,7 +1143,7 @@
 #    mission_desc_2: "We believe that learning computer science can be captivating. It should feel like magic. After all, programming empowers anyone to explore new ideas, to build something from pure imagination, and to interact with each other in new ways. Our goal is to inspire a connection to the creativity and imagination inherent in computer science by building educational games that are creative and imaginative."
 #    mission_desc_3: "Over the last five years, over twelve million people have learned to write Python and JavaScript using CodeCombat, making it one of the most popular coding games in history. Now, we are excited to launch Ozaria and expand on our commitment to inspire a new generation of students to learn computer science. Ozaria is an adventure game that places each learner at the center of a legendary story where they must save the world of Ozaria from impending darkness by mastering the lost magic of coding. As the narrative unfolds, a powerful student-centered learning experience is created - each student’s investment in Ozaria’s story paralleling the investment they are making in their own learning journey."
     team_title: "与CodeCombat团队见面"
-    team_values: "我们期待开放的、互相尊敬的对话，好点子会得到采纳。我们决定深入市场调研，我们集中于提供实际性的结果。从我们的 CEO 到 Github 上的贡献者，每个人都亲历亲为，因为在团队中我们收获了成长与经验。" # {change}
+    team_values: "我们期待开放的、互相尊敬的对话，好点子会得到采纳。我们决定深入市场调研，我们集中于提供实际性的结果。从我们的 CEO 到 Github 上的贡献者，每个人都亲力亲为，因为在团队中我们收获了成长与经验。"
 #    nick_title: "Cofounder, CEO"
 #    matt_title: "Cofounder, CTO"
 #    cat_title: "Game Designer"
@@ -1182,7 +1183,7 @@
     community_subtitle: "超过 450 个志愿者帮助我们建设 CodeCombat，每周都有新成员加入！" # {change}
     community_description_3: "CodeCombat 是一个"
     community_description_link_2: "开源的社区项目"
-    community_description_1: "，上百名玩家创建了各种关卡，给我们的源代码添砖加瓦，添加新功能、修复Bug、测试、甚至是将其翻译为50种语言。职员、贡献者以及网站本身都在分享创意并奋斗中成长，这就是开源社区的力量。此网站在众多开源项目之上建立，我们为表感恩，也将网站开源奉献给社区，给好奇源码的玩家提供探索和实验的项目。每个人都能加入CodeCombat社区！看一下我们的" # {change}
+    community_description_1: "上百名玩家创建了各种关卡，给我们的源代码添砖加瓦，添加新功能、修复Bug、测试、甚至是将其翻译为50种语言。职员、贡献者以及网站本身都在分享创意并奋斗中成长，这就是开源社区的力量。此网站在众多开源项目之上建立，我们为表感恩，也将网站开源奉献给社区，给好奇源码的玩家提供探索和实验的项目。每个人都能加入CodeCombat社区！看一下我们的" # {change}
     community_description_link: "贡献者页面"
     community_description_2: "了解更多信息。"
     number_contributors: "超过 450 个志愿者将他们的知识和时间投入到这个项目中。"
@@ -1192,7 +1193,7 @@
     story_statistic_1b: "总玩家"
     story_statistic_1c: "已经通过CodeCombat开始了他们的编程之旅" # {change}
     story_statistic_2a: "我们将这个游戏翻译为超过 50 种语言 —— 得益于来自"
-    story_statistic_2b: "200+ 个国家" # {change}
+    story_statistic_2b: "190+ 个国家" # {change}
     story_statistic_3a: "的玩家，他们总共写下了"
     story_statistic_3b: "10亿行代码和说明"
     story_statistic_3c: "，涵盖了多种编程语言。"
@@ -1239,7 +1240,7 @@
     low_price_title: "每个学生仅仅只要 __starterLicensePrice__ 元 "
     low_price_description: "学生入门许可证在购买后的 __starterLicenseLengthMonths__ 个月内有效."
     three_great_courses: "学生入门许可证中包含三个伟大的课程:"
-    license_limit_description: "老师最多可以购买 __maxQuantityStarterLicenses__ 个许可证. 你已经购买了 __quantityAlreadyPurchased__ 个. 如果你需要更多, 请联系 bill@codecombat.com. 学生入门许可证有效期为 __starterLicenseLengthMonths__ 个月."
+    license_limit_description: "老师最多可以购买 __maxQuantityStarterLicenses__ 个许可证. 你已经购买了 __quantityAlreadyPurchased__ 个. 如果你需要更多, 请联系 china@codecombat.com. 学生入门许可证有效期为 __starterLicenseLengthMonths__ 个月."
     student_starter_license: "学生入门许可"
     purchase_starter_licenses: "购买入门许可证"
     purchase_starter_licenses_to_grant: "购买入门许可证可被授权访问 __starterLicenseCourseList__"
@@ -1274,8 +1275,8 @@
   teachers_quote:
     subtitle: "将 CodeCombat 带到您的班级、俱乐部、学校甚至地区！" # {change}
     email_exists: "使用该账号的电子邮箱"
-    phone_number: "电话号码"
-    phone_number_help: "工作日时我们在哪可以找到您？"
+    phone_number: "手机号码"
+    phone_number_help: "工作日我们如何找到您？"
     primary_role_label: "您的主要职业"
     role_default: "选择职业"
     primary_role_default: "（请选择）"
@@ -1291,12 +1292,12 @@
     approve_funds: "批准资金"
     no_purchaser_role: "不参与购买决策"
     district_label: "地区"
-    district_name: "区"
+    district_name: "区/县"
     district_na: "不可用时请输入 N/A"
     organization_label: "学校："
-    school_name: "学校名称"
-    city: "城市"
-    state: "省" # {change}
+    school_name: "学校或机构名称"
+    city: "市（直辖市可填无）"
+    state: "省/直辖市" # {change}
     country: "国家"
     num_students_help: "您估计有多少学生加入CodeCombat？" # {change}
     num_students_default: "选择数量范围"
@@ -1333,7 +1334,7 @@
     create_account_subtitle: "在 CodeCombat 班级中使用老师专用工具。 创建班级添加学生、观察学生进度！"
     convert_account_title: "升级为老师账号"
     not: "不是"
-#    full_name_required: "First and last name required"
+    full_name_required: "姓和名是必填项"

   versions:
     save_version_title: "保存新版本"
@@ -1423,8 +1424,8 @@
     beautify: "利用标准编码格式美化您的代码。"
     maximize_editor: "最大化/最小化代码编辑器"

-#  cinematic:
-#    click_anywhere_continue: "click anywhere to continue"
+  cinematic:
+    click_anywhere_continue: "点击任意区域继续"

   community:
     main_title: "CodeCombat社区"
@@ -1562,7 +1563,7 @@
     play_now_learn_2: "解决麻烦谜题的while循环"
     play_now_learn_3: "自定义动作的字符串和变量"
     play_now_learn_4: "如何打败食人魔（重要生存技巧！）"
-    welcome_to_page: "欢迎来到你的课程页面！" # {change}
+    welcome_to_page: "欢迎来到我的课程！"
     my_classes: "我的课程" # {change}
     class_added: "成功添加课程！"
     view_map: "查看地图"
@@ -1574,7 +1575,7 @@
     enter_c_code: "<输入班级代码>" # {change}
     join: "加入"
     joining: "加入课程中"
-#    unit_complete: "Unit Complete"
+    unit_complete: "已完成"
     play_arena: "玩竞技场"
     view_project: "查看项目"
     start: "开始"
@@ -1586,7 +1587,7 @@
     are_you_sure: "你确定要从该课程中删除该学生吗？"
     remove_description1: "学生将失去访问该课程和被分派课程的权利。游戏进度不会丢失，该学生可以在任何时间被添加回该班级。"
     remove_description2: "被激活的付费许可证将无法返还。"
-#    license_will_revoke: "This student's paid license will be revoked and made available to assign to another student."
+    license_will_revoke: "该学生付费许可将被撤销，稍后可以分配给其他学生"
     keep_student: "保留学生"
     removing_user: "删除用户"
     subtitle: "复习课程指导、解法和关卡" # {change}
@@ -1782,7 +1783,7 @@
     revoke_license: "终止许可"
     revoke_licenses: "终止所有许可"
     course_progress: "课程进度"
-#    unit_progress: "Unit Progress"
+    unit_progress: "课程进度"
     not_applicable: "N/A"
     edit: "修改"
     edit_2: "修改"
@@ -1822,7 +1823,7 @@
 #    not_assigned_modal_starter_body_2: "Purchase Starter Licenses to grant access to this course."
     not_assigned_modal_full_body_1: "本课程需要许可证才能使用。您没有足够的许可证, 因此无法将此课程分配给已选定的 __selected__ 名学生。" # {change}
     not_assigned_modal_full_body_2: "您当前仅有__numFullLicensesAvailable__个许可证可供使用 (__numStudentsWithoutFullLicenses__名学生目前没有许可证) 。"
-    not_assigned_modal_full_body_3: "请适量减少选定的学生数量, 或联系bill@codecombat.com寻求帮助。"
+    not_assigned_modal_full_body_3: "请适量减少选定的学生数量, 或联系china@codecombat.com寻求帮助。"
     assigned: "已添加"
     enroll_selected_students: "注册选中的学生"
     no_students_selected: "没有学生被选中。"
@@ -2051,7 +2052,7 @@
     sync_google_classroom: "同步谷歌教室"
 #    implementation_guide: "Implementation Options - Ozaria and CodeCombat"
 #    implementation_guide_desc: "Options for bridging Ozaria and CodeCombat content based on the structure and focus of your classroom."
-#    prologue: "Prologue: The Sky Mountain"
+    prologue: "序章: 天山"
 #    unit_overview: "Unit Overview"
 #    module_overview: "Module Overview"
 #    prologue_unit_overview_desc: "Summary of student experience, including Cutscenes, Practice Levels, Intros, and the Capstone project in the Prologue Unit."
@@ -2419,12 +2420,12 @@
     left_xp_postfix: ""

   account:
-#    title: "Account"
-#    settings_title: "Account Settings"
-#    unsubscribe_title: "Unsubscribe"
-#    payments_title: "Payments"
-#    subscription_title: "Subscription"
-#    invoices_title: "Invoices"
+    title: "账户"
+    settings_title: "账户设置"
+    unsubscribe_title: "取消订阅"
+    payments_title: "支付"
+    subscription_title: "订阅"
+    invoices_title: "发票"
 #    prepaids_title: "Prepaids"
     payments: "支付方式"
     prepaid_codes: "预付费码"
@@ -2546,8 +2547,8 @@
     arithmetic: "四则运算"
     array_2d: "二维数组"
     array_index: "数组下标"
-#    array_iterating: "Iterating Over Arrays"
-#    array_literals: "Array Literals"
+    array_iterating: "数组迭代"
+    array_literals: "数组字面量"
     array_searching: "数组遍历"
     array_sorting: "数组排序"
     arrays: "数组"
@@ -2589,7 +2590,7 @@
     game_goals: "游戏目标"
 #    game_spawn: "Game Spawn"
     graphics: "图形"
-#    graphs: "Graphs"
+    graphs: "图"
     heaps: "堆"
     if_condition: "If条件语句"
     if_else_if: "If/Else If语句"
@@ -2610,7 +2611,7 @@
     jquery_selectors: "jQuery选择器"
     length: "数组长度"
 #    math_coordinates: "Coordinate Math"
-#    math_geometry: "Geometry"
+    math_geometry: "几何"
     math_operations: "数学程序库操作"
 #    math_proportions: "Proportion Math"
 #    math_trigonometry: "Trigonometry"
@@ -2637,7 +2638,7 @@
     while_condition_loops: "使用条件语句的While循环"
     while_loops_simple: "While循环"
     while_loops_nested: "While嵌套循环"
-#    xy_coordinates: "Coordinate Pairs"
+    xy_coordinates: "坐标对"
     advanced_strings: "高级字符串" # Rest of concepts are deprecated
     algorithms: "算法"
     boolean_logic: "布尔逻辑"
@@ -3023,7 +3024,7 @@
     projects_created: "学生作品数"
     other: "其他"
     notice: "以下学校管理员对您的课堂数据有查看权限："
-    add_additional_teacher: "需要添加其他的教师吗？请联系您的CodeCombat客户经理或发送电子邮件至bill@codecombat.com。 "
+    add_additional_teacher: "需要添加其他的教师吗？请联系您的CodeCombat客户经理或发送电子邮件至china@codecombat.com。 "
     license_stat_description: "可用许可证是教师可用的许可证总数，包括共享的许可证。"
     students_stat_description: "学生总数是所有教室的所有学生数，不管他们是否使用了许可证，都会被计算在内。"
     active_students_stat_description: "活跃学生数是在过去60天登录CodeCombat的学生人数。"


Update ： employers for Chinese simplified

Update ： employers for Chinese simplified

--- app/locale/zh-HANS.coffee
+++ app/locale/zh-HANS.coffee
@@ -31,7 +31,7 @@
     about: "关于"
     contact: "联系"
     twitter_follow: "关注"
-    employers: "雇佣我们"
+    employers: "招募信息"

   versions:
     save_version_title: "保存新版本"


new zh-hans translation

new zh-hans translation

add the the tournament translation

--- app/locale/zh-HANT.coffee
+++ app/locale/zh-HANT.coffee
@@ -1078,6 +1078,7 @@
     tournament_blurb: "寫下程式碼, 收集金幣, 建立軍隊, 粉碎敵人, 贏得獎項,在我們價值$40,000的Greed錦標賽中升級您的職業! 查看"
     tournament_blurb_criss_cross: "贏得競賽, 建造道路, 智勝對手, 收集寶石, 在我們的Criss-Crossand錦標賽中升級您的職業! 查看"
     tournament_blurb_zero_sum: "在紅方法師和藍方法師的山峰對決中，同時在收集金幣和戰術上發揮你的代碼創造力。競賽在3月27日開始，在4月6日（星期一）的下午5點（PDT太平洋時區）結束。為樂趣和榮耀競賽吧！瀏覽了解更多"
+    tournament_blurb_ace_of_coders: "我的主场我主宰，在天寒地冻的冰山上来自己镜像大战一场吧！本次比赛将由9月16日星期三开办到10月14日下午5点PDT。详情请查看"
     tournament_blurb_blog: "我們的部落格"
     rules: "規則"
     winners: "贏家"


adding complete documentation for the grammar

--- grammar.coffee
+++ grammar.coffee
@@ -1,20 +1,521 @@
+# The CoffeeScript parser is generated by [Jison](http://github.com/zaach/jison)
+# from this grammar file. Jison is a bottom-up parser generator, similar in
+# style to [Bison](http://www.gnu.org/software/bison), implemented in JavaScript.
+# It can recognize [LALR(1), LR(0), SLR(1), and LR(1)](http://en.wikipedia.org/wiki/LR_grammar)
+# type grammars. To create the Jison parser, we list the pattern to match
+# on the left-hand side, and the action to take (usually the creation of syntax
+# tree nodes) on the right. As the parser runs, it
+# shifts tokens from our token stream, from left to right, and
+# [attempts to match](http://en.wikipedia.org/wiki/Bottom-up_parsing)
+# the token sequence against the rules below. When a match can be made, it
+# reduces into the [nonterminal](http://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols)
+# (the enclosing name at the top), and we proceed from there.
+#
+# If you run the `cake build:parser` command, Jison constructs a parse table
+# from our rules and saves it into `lib/parser.js`.
+
+# The only dependency is on the **Jison.Parser**.
 Parser: require('jison').Parser

-# DSL ===================================================================
-
-# Detect functions: [
+# Jison DSL
+# ---------
+
+# Since we're going to be wrapped in a function by Jison in any case, if our
+# action immediately returns a value, we can optimize by removing the function
+# wrapper and just returning the value directly.
 unwrap: /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/

-# Quickie DSL for Jison access.
-o: (pattern_string, func, options) ->
-  if func
-    func: if match: (func + '').match(unwrap) then match[1] else "($func())"
-    [pattern_string, "$$ = $func;", options]
-  else
-    [pattern_string, '$$ = $1;', options]
-
-# Precedence ===========================================================
-
+# Our handy DSL for Jison grammar generation, thanks to
+# [Tim Caswell](http://github.com/creationix). For every rule in the grammar,
+# we pass the pattern-defining string, the action to run, and extra options,
+# optionally. If no action is specified, we simply pass the value of the
+# previous nonterminal.
+o: (pattern_string, action, options) ->
+  return [pattern_string, '$$ = $1;', options] unless action
+  action: if match: (action + '').match(unwrap) then match[1] else "($action())"
+  [pattern_string, "$$ = $action;", options]
+
+# Grammatical Rules
+# -----------------
+
+# In all of the rules that follow, you'll see the name of the nonterminal as
+# the key to a list of alternative matches. With each match's action, the
+# dollar-sign variables are provided by Jison as references to the value of
+# their numeric position, so in this rule:
+#
+#     "Expression UNLESS Expression"
+#
+# `$1` would be the value of the first `Expression`, `$2` would be the token
+# for the `UNLESS` terminal, and `$3` would be the value of the second
+# `Expression`.
+grammar: {
+
+  # The **Root** is the top-level node in the syntax tree. Since we parse bottom-up,
+  # all parsing must end here.
+  Root: [
+    o "",                                  -> new Expressions()
+    o "TERMINATOR",                        -> new Expressions()
+    o "Expressions"
+    o "Block TERMINATOR"
+  ]
+
+  # Any list of expressions or method body, seperated by line breaks or
+  # semicolons.
+  Expressions: [
+    o "Expression",                        -> Expressions.wrap [$1]
+    o "Expressions TERMINATOR Expression", -> $1.push $3
+    o "Expressions TERMINATOR"
+  ]
+
+  # All the different types of expressions in our language. The basic unit of
+  # CoffeeScript is the **Expression** -- you'll notice that there is no
+  # "statement" nonterminal. Expressions serve as the building blocks
+  # of many other rules, making them somewhat circular.
+  Expression: [
+    o "Value"
+    o "Call"
+    o "Code"
+    o "Operation"
+    o "Assign"
+    o "If"
+    o "Try"
+    o "Throw"
+    o "Return"
+    o "While"
+    o "For"
+    o "Switch"
+    o "Extends"
+    o "Class"
+    o "Splat"
+    o "Existence"
+    o "Comment"
+  ]
+
+  # A an indented block of expressions. Note that the [Rewriter](rewriter.html)
+  # will convert some postfix forms into blocks for us, by adjusting the
+  # token stream.
+  Block: [
+    o "INDENT Expressions OUTDENT",             -> $2
+    o "INDENT OUTDENT",                         -> new Expressions()
+  ]
+
+  # A literal identifier, a variable name or property.
+  Identifier: [
+    o "IDENTIFIER",                             -> new LiteralNode yytext
+  ]
+
+  # Alphanumerics are separated from the other **Literal** matchers because
+  # they can also serve as keys in object literals.
+  AlphaNumeric: [
+    o "NUMBER",                                 -> new LiteralNode yytext
+    o "STRING",                                 -> new LiteralNode yytext
+  ]
+
+  # All of our immediate values. These can (in general), be passed straight
+  # through and printed to JavaScript.
+  Literal: [
+    o "AlphaNumeric"
+    o "JS",                                     -> new LiteralNode yytext
+    o "REGEX",                                  -> new LiteralNode yytext
+    o "BREAK",                                  -> new LiteralNode yytext
+    o "CONTINUE",                               -> new LiteralNode yytext
+    o "TRUE",                                   -> new LiteralNode true
+    o "FALSE",                                  -> new LiteralNode false
+    o "YES",                                    -> new LiteralNode true
+    o "NO",                                     -> new LiteralNode false
+    o "ON",                                     -> new LiteralNode true
+    o "OFF",                                    -> new LiteralNode false
+  ]
+
+  # Assignment of a variable, property, or index to a value.
+  Assign: [
+    o "Value ASSIGN Expression",                -> new AssignNode $1, $3
+  ]
+
+  # Assignment when it happens within an object literal. The difference from
+  # the ordinary **Assign** is that these allow numbers and strings as keys.
+  AssignObj: [
+    o "Identifier ASSIGN Expression",           -> new AssignNode new ValueNode($1), $3, 'object'
+    o "AlphaNumeric ASSIGN Expression",         -> new AssignNode new ValueNode($1), $3, 'object'
+    o "Comment"
+  ]
+
+  # A return statement from a function body.
+  Return: [
+    o "RETURN Expression",                      -> new ReturnNode $2
+    o "RETURN",                                 -> new ReturnNode new ValueNode new LiteralNode 'null'
+  ]
+
+  # A comment. Because CoffeeScript passes comments through to JavaScript, we
+  # have to parse comments like any other construct, and identify all of the
+  # positions in which they can occur in the grammar.
+  Comment: [
+    o "COMMENT",                                -> new CommentNode yytext
+  ]
+
+  # [The existential operator](http://jashkenas.github.com/coffee-script/#existence).
+  Existence: [
+    o "Expression ?",                           -> new ExistenceNode $1
+  ]
+
+  # The **Code** node is the function literal. It's defined by an indented block
+  # of **Expressions** preceded by a function arrow, with an optional parameter
+  # list.
+  Code: [
+    o "PARAM_START ParamList PARAM_END FuncGlyph Block", -> new CodeNode $2, $5, $4
+    o "FuncGlyph Block",                        -> new CodeNode [], $2, $1
+  ]
+
+  # CoffeeScript has two different symbols for functions. `->` is for ordinary
+  # functions, and `=>` is for functions bound to the current value of *this*.
+  FuncGlyph: [
+    o "->",                                     -> 'func'
+    o "=>",                                     -> 'boundfunc'
+  ]
+
+  # The list of parameters that a function accepts can be of any length.
+  ParamList: [
+    o "",                                       -> []
+    o "Param",                                  -> [$1]
+    o "ParamList , Param",                      -> $1.concat [$3]
+  ]
+
+  # A single parameter in a function definition can be ordinary, or a splat
+  # that hoovers up the remaining arguments.
+  Param: [
+    o "PARAM",                                  -> new LiteralNode yytext
+    o "Param . . .",                            -> new SplatNode $1
+  ]
+
+  # A splat that occurs outside of a parameter list.
+  Splat: [
+    o "Expression . . .",                       -> new SplatNode $1
+  ]
+
+  # The types of things that can be treated as values -- assigned to, invoked
+  # as functions, indexed into, named as a class, etc.
+  Value: [
+    o "Identifier",                             -> new ValueNode $1
+    o "Literal",                                -> new ValueNode $1
+    o "Array",                                  -> new ValueNode $1
+    o "Object",                                 -> new ValueNode $1
+    o "Parenthetical",                          -> new ValueNode $1
+    o "Range",                                  -> new ValueNode $1
+    o "This"
+    o "Value Accessor",                         -> $1.push $2
+    o "Invocation Accessor",                    -> new ValueNode $1, [$2]
+  ]
+
+  # The general group of accessors into an object, by property, by prototype
+  # or by array index or slice.
+  Accessor: [
+    o "PROPERTY_ACCESS Identifier",             -> new AccessorNode $2
+    o "PROTOTYPE_ACCESS Identifier",            -> new AccessorNode $2, 'prototype'
+    o "SOAK_ACCESS Identifier",                 -> new AccessorNode $2, 'soak'
+    o "Index"
+    o "Slice",                                  -> new SliceNode $1
+  ]
+
+  # Indexing into an object or array using bracket notation.
+  Index: [
+    o "INDEX_START Expression INDEX_END",       -> new IndexNode $2
+    o "SOAKED_INDEX_START Expression SOAKED_INDEX_END", -> new IndexNode $2, 'soak'
+  ]
+
+  # In CoffeeScript, an object literal is simply a list of assignments.
+  Object: [
+    o "{ AssignList }",                         -> new ObjectNode $2
+    o "{ IndentedAssignList }",                 -> new ObjectNode $2
+  ]
+
+  # Class definitions have optional bodies of prototype property assignments,
+  # and optional references to the superclass.
+  Class: [
+    o "CLASS Value",                            -> new ClassNode $2
+    o "CLASS Value EXTENDS Value",              -> new ClassNode $2, $4
+    o "CLASS Value IndentedAssignList",         -> new ClassNode $2, null, $3
+    o "CLASS Value EXTENDS Value IndentedAssignList", -> new ClassNode $2, $4, $5
+  ]
+
+  # Assignment of properties within an object literal can be separated by
+  # comma, as in JavaScript, or simply by newline.
+  AssignList: [
+    o "",                                       -> []
+    o "AssignObj",                              -> [$1]
+    o "AssignList , AssignObj",                 -> $1.concat [$3]
+    o "AssignList TERMINATOR AssignObj",        -> $1.concat [$3]
+    o "AssignList , TERMINATOR AssignObj",      -> $1.concat [$4]
+  ]
+
+  # An **AssignList** within a block indentation.
+  IndentedAssignList: [
+    o "INDENT AssignList OUTDENT",              -> $2
+  ]
+
+  # The three flavors of function call: normal, object instantiation with `new`,
+  # and calling `super()`
+  Call: [
+    o "Invocation"
+    o "NEW Invocation",                         -> $2.new_instance()
+    o "Super"
+  ]
+
+  # Extending an object by setting its prototype chain to reference a parent
+  # object.
+  Extends: [
+    o "Value EXTENDS Value",                    -> new ExtendsNode $1, $3
+  ]
+
+  # Ordinary function invocation, or a chained series of calls.
+  Invocation: [
+    o "Value Arguments",                        -> new CallNode $1, $2
+    o "Invocation Arguments",                   -> new CallNode $1, $2
+  ]
+
+  # The list of arguments to a function call.
+  Arguments: [
+    o "CALL_START ArgList CALL_END",            -> $2
+  ]
+
+  # Calling super.
+  Super: [
+    o "SUPER CALL_START ArgList CALL_END",      -> new CallNode 'super', $3
+  ]
+
+  # A reference to the *this* current object, either naked or to a property.
+  This: [
+    o "@",                                      -> new ValueNode new LiteralNode 'this'
+    o "@ Identifier",                           -> new ValueNode new LiteralNode('this'), [new AccessorNode($2)]
+  ]
+
+  # The CoffeeScript range literal.
+  Range: [
+    o "[ Expression . . Expression ]",          -> new RangeNode $2, $5
+    o "[ Expression . . . Expression ]",        -> new RangeNode $2, $6, true
+  ]
+
+  # The slice literal.
+  Slice: [
+    o "INDEX_START Expression . . Expression INDEX_END", -> new RangeNode $2, $5
+    o "INDEX_START Expression . . . Expression INDEX_END", -> new RangeNode $2, $6, true
+  ]
+
+  # The array literal.
+  Array: [
+    o "[ ArgList ]",                            -> new ArrayNode $2
+  ]
+
+  # The **ArgList** is both the list of objects passed into a function call,
+  # as well as the contents of an array literal
+  # (i.e. comma-separated expressions). Newlines work as well.
+  ArgList: [
+    o "",                                       -> []
+    o "Expression",                             -> [$1]
+    o "INDENT Expression",                      -> [$2]
+    o "ArgList , Expression",                   -> $1.concat [$3]
+    o "ArgList TERMINATOR Expression",          -> $1.concat [$3]
+    o "ArgList , TERMINATOR Expression",        -> $1.concat [$4]
+    o "ArgList , INDENT Expression",            -> $1.concat [$4]
+    o "ArgList OUTDENT"
+  ]
+
+  # Just simple, comma-separated, required arguments (no fancy syntax). We need
+  # this to be separate from the **ArgList** for use in **Switch** blocks, where
+  # having the newlines wouldn't make sense.
+  SimpleArgs: [
+    o "Expression"
+    o "SimpleArgs , Expression",                ->
+      if $1 instanceof Array then $1.concat([$3]) else [$1].concat([$3])
+  ]
+
+  # The variants of *try/catch/finally* exception handling blocks.
+  Try: [
+    o "TRY Block Catch",                        -> new TryNode $2, $3[0], $3[1]
+    o "TRY Block FINALLY Block",                -> new TryNode $2, null, null, $4
+    o "TRY Block Catch FINALLY Block",          -> new TryNode $2, $3[0], $3[1], $5
+  ]
+
+  # A catch clause names its error and runs a block of code.
+  Catch: [
+    o "CATCH Identifier Block",                 -> [$2, $3]
+  ]
+
+  # Throw an exception object.
+  Throw: [
+    o "THROW Expression",                       -> new ThrowNode $2
+  ]
+
+  # Parenthetical expressions. Note that the **Parenthetical** is a **Value**,
+  # not an **Expression**, so if you need to use an expression in a place
+  # where only values are accepted, wrapping it in parentheses will always do
+  # the trick.
+  Parenthetical: [
+    o "( Expression )",                         -> new ParentheticalNode $2
+  ]
+
+  # The condition portion of a while loop.
+  WhileSource: [
+    o "WHILE Expression",                       -> new WhileNode $2
+    o "WHILE Expression WHEN Expression",       -> new WhileNode $2, {filter : $4}
+  ]
+
+  # The while loop can either be normal, with a block of expressions to execute,
+  # or postfix, with a single expression. There is no do..while.
+  While: [
+    o "WhileSource Block",                      -> $1.add_body $2
+    o "Expression WhileSource",                 -> $2.add_body $1
+  ]
+
+  # Array, object, and range comprehensions, at the most generic level.
+  # Comprehensions can either be normal, with a block of expressions to execute,
+  # or postfix, with a single expression.
+  For: [
+    o "Expression FOR ForVariables ForSource",  -> new ForNode $1, $4, $3[0], $3[1]
+    o "FOR ForVariables ForSource Block",       -> new ForNode $4, $3, $2[0], $2[1]
+  ]
+
+  # An array or range comprehension has variables for the current element and
+  # (optional) reference to the current index. Or, *key, value*, in the case
+  # of object comprehensions.
+  ForVariables: [
+    o "Identifier",                             -> [$1]
+    o "Identifier , Identifier",                -> [$1, $3]
+  ]
+
+  # The source of a comprehension is an array or object with an optional filter
+  # clause. If it's an array comprehension, you can also choose to step throug
+  # in fixed-size increments.
+  ForSource: [
+    o "IN Expression",                          -> {source:   $2}
+    o "OF Expression",                          -> {source:   $2, object: true}
+    o "ForSource WHEN Expression",              -> $1.filter: $3; $1
+    o "ForSource BY Expression",                -> $1.step:   $3; $1
+  ]
+
+  # The CoffeeScript switch/when/else block replaces the JavaScript
+  # switch/case/default by compiling into an if-else chain.
+  Switch: [
+    o "SWITCH Expression INDENT Whens OUTDENT", -> $4.rewrite_condition $2
+    o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.rewrite_condition($2).add_else $6, true
+  ]
+
+  # The inner list of whens is left recursive. At code-generation time, the
+  # IfNode will rewrite them into a proper chain.
+  Whens: [
+    o "When"
+    o "Whens When",                             -> $1.push $2
+  ]
+
+  # An individual **When** clause, with action.
+  When: [
+    o "LEADING_WHEN SimpleArgs Block",          -> new IfNode $2, $3, null, {statement: true}
+    o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> new IfNode $2, $3, null, {statement: true}
+    o "Comment TERMINATOR When",                -> $3.comment: $1; $3
+  ]
+
+  # The most basic form of *if* is a condition and an action. The following
+  # if-related rules are broken up along these lines in order to avoid
+  # ambiguity.
+  IfStart: [
+    o "IF Expression Block",                    -> new IfNode $2, $3
+    o "IfStart ElsIf",                          -> $1.add_else $2
+  ]
+
+  # An **IfStart** can optionally be followed by an else block.
+  IfBlock: [
+    o "IfStart"
+    o "IfStart ELSE Block",                     -> $1.add_else $3
+  ]
+
+  # An *else if* continuation of the *if* expression.
+  ElsIf: [
+    o "ELSE IF Expression Block",               -> (new IfNode($3, $4)).force_statement()
+  ]
+
+  # The full complement of *if* expressions, including postfix one-liner
+  # *if* and *unless*.
+  If: [
+    o "IfBlock"
+    o "Expression IF Expression",               -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true}
+    o "Expression UNLESS Expression",           -> new IfNode $3, Expressions.wrap([$1]), null, {statement: true, invert: true}
+  ]
+
+  # Arithmetic and logical operators, working on one or more operands.
+  # Here they are grouped by order of precedence. The actual precedence rules
+  # are defined at the bottom of the page. It would be shorter if we could
+  # combine most of these rules into a single generic *Operand OpSymbol Operand*
+  # -type rule, but in order to make the precedence binding possible, separate
+  # rules are necessary.
+  Operation: [
+    o "! Expression",                           -> new OpNode '!', $2
+    o "!! Expression",                          -> new OpNode '!!', $2
+    o("- Expression",                           (-> new OpNode('-', $2)), {prec: 'UMINUS'})
+    o("+ Expression",                           (-> new OpNode('+', $2)), {prec: 'UPLUS'})
+    o "NOT Expression",                         -> new OpNode 'not', $2
+    o "~ Expression",                           -> new OpNode '~', $2
+    o "-- Expression",                          -> new OpNode '--', $2
+    o "++ Expression",                          -> new OpNode '++', $2
+    o "DELETE Expression",                      -> new OpNode 'delete', $2
+    o "TYPEOF Expression",                      -> new OpNode 'typeof', $2
+    o "Expression --",                          -> new OpNode '--', $1, null, true
+    o "Expression ++",                          -> new OpNode '++', $1, null, true
+
+    o "Expression * Expression",                -> new OpNode '*', $1, $3
+    o "Expression / Expression",                -> new OpNode '/', $1, $3
+    o "Expression % Expression",                -> new OpNode '%', $1, $3
+
+    o "Expression + Expression",                -> new OpNode '+', $1, $3
+    o "Expression - Expression",                -> new OpNode '-', $1, $3
+
+    o "Expression << Expression",               -> new OpNode '<<', $1, $3
+    o "Expression >> Expression",               -> new OpNode '>>', $1, $3
+    o "Expression >>> Expression",              -> new OpNode '>>>', $1, $3
+    o "Expression & Expression",                -> new OpNode '&', $1, $3
+    o "Expression | Expression",                -> new OpNode '|', $1, $3
+    o "Expression ^ Expression",                -> new OpNode '^', $1, $3
+
+    o "Expression <= Expression",               -> new OpNode '<=', $1, $3
+    o "Expression < Expression",                -> new OpNode '<', $1, $3
+    o "Expression > Expression",                -> new OpNode '>', $1, $3
+    o "Expression >= Expression",               -> new OpNode '>=', $1, $3
+
+    o "Expression == Expression",               -> new OpNode '==', $1, $3
+    o "Expression != Expression",               -> new OpNode '!=', $1, $3
+    o "Expression IS Expression",               -> new OpNode 'is', $1, $3
+    o "Expression ISNT Expression",             -> new OpNode 'isnt', $1, $3
+
+    o "Expression && Expression",               -> new OpNode '&&', $1, $3
+    o "Expression || Expression",               -> new OpNode '||', $1, $3
+    o "Expression AND Expression",              -> new OpNode 'and', $1, $3
+    o "Expression OR Expression",               -> new OpNode 'or', $1, $3
+    o "Expression ? Expression",                -> new OpNode '?', $1, $3
+
+    o "Expression -= Expression",               -> new OpNode '-=', $1, $3
+    o "Expression += Expression",               -> new OpNode '+=', $1, $3
+    o "Expression /= Expression",               -> new OpNode '/=', $1, $3
+    o "Expression *= Expression",               -> new OpNode '*=', $1, $3
+    o "Expression %= Expression",               -> new OpNode '%=', $1, $3
+    o "Expression ||= Expression",              -> new OpNode '||=', $1, $3
+    o "Expression &&= Expression",              -> new OpNode '&&=', $1, $3
+    o "Expression ?= Expression",               -> new OpNode '?=', $1, $3
+
+    o "Expression INSTANCEOF Expression",       -> new OpNode 'instanceof', $1, $3
+    o "Expression IN Expression",               -> new OpNode 'in', $1, $3
+  ]
+
+}
+
+# Precedence
+# ----------
+
+# Operators at the top of this list have higher precedence than the ones lower
+# down. Following these rules is what makes `2 + 3 * 4` parse as:
+#
+#     2 + (3 * 4)
+#
+# And not:
+#
+#     (2 + 3) * 4
 operators: [
   ["left",      '?']
   ["nonassoc",  'UMINUS', 'UPLUS', 'NOT', '!', '!!', '~', '++', '--']
@@ -37,434 +538,28 @@
   ["right",     '->', '=>', 'UNLESS', 'IF', 'ELSE', 'WHILE']
 ]

-# Grammar ==============================================================
-
-grammar: {
-
-  # All parsing will end in this rule, being the trunk of the AST.
-  Root: [
-    o "",                                  -> new Expressions()
-    o "TERMINATOR",                        -> new Expressions()
-    o "Expressions",                       -> $1
-    o "Block TERMINATOR",                  -> $1
-  ]
-
-  # Any list of expressions or method body, seperated by line breaks or semis.
-  Expressions: [
-    o "Expression",                        -> Expressions.wrap([$1])
-    o "Expressions TERMINATOR Expression", -> $1.push($3)
-    o "Expressions TERMINATOR",            -> $1
-  ]
-
-  # All types of expressions in our language. The basic unit of CoffeeScript
-  # is the expression.
-  Expression: [
-    o "Value"
-    o "Call"
-    o "Code"
-    o "Operation"
-    o "Assign"
-    o "If"
-    o "Try"
-    o "Throw"
-    o "Return"
-    o "While"
-    o "For"
-    o "Switch"
-    o "Extends"
-    o "Class"
-    o "Splat"
-    o "Existence"
-    o "Comment"
-  ]
-
-  # A block of expressions. Note that the Rewriter will convert some postfix
-  # forms into blocks for us, by altering the token stream.
-  Block: [
-    o "INDENT Expressions OUTDENT",             -> $2
-    o "INDENT OUTDENT",                         -> new Expressions()
-  ]
-
-  Identifier: [
-    o "IDENTIFIER",                             -> new LiteralNode(yytext)
-  ]
-
-  AlphaNumeric: [
-    o "NUMBER",                                 -> new LiteralNode(yytext)
-    o "STRING",                                 -> new LiteralNode(yytext)
-  ]
-
-  # All hard-coded values. These can be printed straight to JavaScript.
-  Literal: [
-    o "AlphaNumeric",                           -> $1
-    o "JS",                                     -> new LiteralNode(yytext)
-    o "REGEX",                                  -> new LiteralNode(yytext)
-    o "BREAK",                                  -> new LiteralNode(yytext)
-    o "CONTINUE",                               -> new LiteralNode(yytext)
-    o "TRUE",                                   -> new LiteralNode(true)
-    o "FALSE",                                  -> new LiteralNode(false)
-    o "YES",                                    -> new LiteralNode(true)
-    o "NO",                                     -> new LiteralNode(false)
-    o "ON",                                     -> new LiteralNode(true)
-    o "OFF",                                    -> new LiteralNode(false)
-  ]
-
-  # Assignment to a variable (or index).
-  Assign: [
-    o "Value ASSIGN Expression",                -> new AssignNode($1, $3)
-  ]
-
-  # Assignment within an object literal (can be quoted).
-  AssignObj: [
-    o "Identifier ASSIGN Expression",           -> new AssignNode(new ValueNode($1), $3, 'object')
-    o "AlphaNumeric ASSIGN Expression",         -> new AssignNode(new ValueNode($1), $3, 'object')
-    o "Comment"
-  ]
-
-  # A return statement.
-  Return: [
-    o "RETURN Expression",                      -> new ReturnNode($2)
-    o "RETURN",                                 -> new ReturnNode(new ValueNode(new LiteralNode('null')))
-  ]
-
-  # A comment.
-  Comment: [
-    o "COMMENT",                                -> new CommentNode(yytext)
-  ]
-
-  # Arithmetic and logical operators
-  # For Ruby's Operator precedence, see: [
-  # https://www.cs.auckland.ac.nz/references/ruby/ProgrammingRuby/language.html
-  Operation: [
-    o "! Expression",                           -> new OpNode('!', $2)
-    o "!! Expression",                          -> new OpNode('!!', $2)
-    o("- Expression",                           (-> new OpNode('-', $2)), {prec: 'UMINUS'})
-    o("+ Expression",                           (-> new OpNode('+', $2)), {prec: 'UPLUS'})
-    o "NOT Expression",                         -> new OpNode('not', $2)
-    o "~ Expression",                           -> new OpNode('~', $2)
-    o "-- Expression",                          -> new OpNode('--', $2)
-    o "++ Expression",                          -> new OpNode('++', $2)
-    o "DELETE Expression",                      -> new OpNode('delete', $2)
-    o "TYPEOF Expression",                      -> new OpNode('typeof', $2)
-    o "Expression --",                          -> new OpNode('--', $1, null, true)
-    o "Expression ++",                          -> new OpNode('++', $1, null, true)
-
-    o "Expression * Expression",                -> new OpNode('*', $1, $3)
-    o "Expression / Expression",                -> new OpNode('/', $1, $3)
-    o "Expression % Expression",                -> new OpNode('%', $1, $3)
-
-    o "Expression + Expression",                -> new OpNode('+', $1, $3)
-    o "Expression - Expression",                -> new OpNode('-', $1, $3)
-
-    o "Expression << Expression",               -> new OpNode('<<', $1, $3)
-    o "Expression >> Expression",               -> new OpNode('>>', $1, $3)
-    o "Expression >>> Expression",              -> new OpNode('>>>', $1, $3)
-    o "Expression & Expression",                -> new OpNode('&', $1, $3)
-    o "Expression | Expression",                -> new OpNode('|', $1, $3)
-    o "Expression ^ Expression",                -> new OpNode('^', $1, $3)
-
-    o "Expression <= Expression",               -> new OpNode('<=', $1, $3)
-    o "Expression < Expression",                -> new OpNode('<', $1, $3)
-    o "Expression > Expression",                -> new OpNode('>', $1, $3)
-    o "Expression >= Expression",               -> new OpNode('>=', $1, $3)
-
-    o "Expression == Expression",               -> new OpNode('==', $1, $3)
-    o "Expression != Expression",               -> new OpNode('!=', $1, $3)
-    o "Expression IS Expression",               -> new OpNode('is', $1, $3)
-    o "Expression ISNT Expression",             -> new OpNode('isnt', $1, $3)
-
-    o "Expression && Expression",               -> new OpNode('&&', $1, $3)
-    o "Expression || Expression",               -> new OpNode('||', $1, $3)
-    o "Expression AND Expression",              -> new OpNode('and', $1, $3)
-    o "Expression OR Expression",               -> new OpNode('or', $1, $3)
-    o "Expression ? Expression",                -> new OpNode('?', $1, $3)
-
-    o "Expression -= Expression",               -> new OpNode('-=', $1, $3)
-    o "Expression += Expression",               -> new OpNode('+=', $1, $3)
-    o "Expression /= Expression",               -> new OpNode('/=', $1, $3)
-    o "Expression *= Expression",               -> new OpNode('*=', $1, $3)
-    o "Expression %= Expression",               -> new OpNode('%=', $1, $3)
-    o "Expression ||= Expression",              -> new OpNode('||=', $1, $3)
-    o "Expression &&= Expression",              -> new OpNode('&&=', $1, $3)
-    o "Expression ?= Expression",               -> new OpNode('?=', $1, $3)
-
-    o "Expression INSTANCEOF Expression",       -> new OpNode('instanceof', $1, $3)
-    o "Expression IN Expression",               -> new OpNode('in', $1, $3)
-  ]
-
-  # The existence operator.
-  Existence: [
-    o "Expression ?",                           -> new ExistenceNode($1)
-  ]
-
-  # Function definition.
-  Code: [
-    o "PARAM_START ParamList PARAM_END FuncGlyph Block", -> new CodeNode($2, $5, $4)
-    o "FuncGlyph Block",                        -> new CodeNode([], $2, $1)
-  ]
-
-  # The symbols to signify functions, and bound functions.
-  FuncGlyph: [
-    o "->",                                     -> 'func'
-    o "=>",                                     -> 'boundfunc'
-  ]
-
-  # The parameters to a function definition.
-  ParamList: [
-    o "",                                       -> []
-    o "Param",                                  -> [$1]
-    o "ParamList , Param",                      -> $1.concat [$3]
-  ]
-
-  # A Parameter (or ParamSplat) in a function definition.
-  Param: [
-    o "PARAM",                                  -> new LiteralNode(yytext)
-    o "Param . . .",                            -> new SplatNode($1)
-  ]
-
-  # A regular splat.
-  Splat: [
-    o "Expression . . .",                       -> new SplatNode($1)
-  ]
-
-  # Expressions that can be treated as values.
-  Value: [
-    o "Identifier",                             -> new ValueNode($1)
-    o "Literal",                                -> new ValueNode($1)
-    o "Array",                                  -> new ValueNode($1)
-    o "Object",                                 -> new ValueNode($1)
-    o "Parenthetical",                          -> new ValueNode($1)
-    o "Range",                                  -> new ValueNode($1)
-    o "This",                                   -> $1
-    o "Value Accessor",                         -> $1.push($2)
-    o "Invocation Accessor",                    -> new ValueNode($1, [$2])
-  ]
-
-  # Accessing into an object or array, through dot or index notation.
-  Accessor: [
-    o "PROPERTY_ACCESS Identifier",             -> new AccessorNode($2)
-    o "PROTOTYPE_ACCESS Identifier",            -> new AccessorNode($2, 'prototype')
-    o "SOAK_ACCESS Identifier",                 -> new AccessorNode($2, 'soak')
-    o "Index"
-    o "Slice",                                  -> new SliceNode($1)
-  ]
-
-  # Indexing into an object or array.
-  Index: [
-    o "INDEX_START Expression INDEX_END",       -> new IndexNode($2)
-    o "SOAKED_INDEX_START Expression SOAKED_INDEX_END", -> new IndexNode($2, 'soak')
-  ]
-
-  # An object literal.
-  Object: [
-    o "{ AssignList }",                         -> new ObjectNode($2)
-    o "{ IndentedAssignList }",                 -> new ObjectNode($2)
-  ]
-
-  # A class literal.
-  Class: [
-    o "CLASS Value",                            -> new ClassNode($2)
-    o "CLASS Value EXTENDS Value",              -> new ClassNode($2, $4)
-    o "CLASS Value IndentedAssignList",         -> new ClassNode($2, null, $3)
-    o "CLASS Value EXTENDS Value IndentedAssignList", -> new ClassNode($2, $4, $5)
-  ]
-
-  # Assignment within an object literal (comma or newline separated).
-  AssignList: [
-    o "",                                       -> []
-    o "AssignObj",                              -> [$1]
-    o "AssignList , AssignObj",                 -> $1.concat [$3]
-    o "AssignList TERMINATOR AssignObj",        -> $1.concat [$3]
-    o "AssignList , TERMINATOR AssignObj",      -> $1.concat [$4]
-  ]
-
-  # A list of assignments in a block indentation.
-  IndentedAssignList: [
-    o "INDENT AssignList OUTDENT",              -> $2
-  ]
-
-  # All flavors of function call (instantiation, super, and regular).
-  Call: [
-    o "Invocation",                             -> $1
-    o "NEW Invocation",                         -> $2.new_instance()
-    o "Super",                                  -> $1
-  ]
-
-  # Extending an object's prototype.
-  Extends: [
-    o "Value EXTENDS Value",                    -> new ExtendsNode($1, $3)
-  ]
-
-  # A generic function invocation.
-  Invocation: [
-    o "Value Arguments",                        -> new CallNode($1, $2)
-    o "Invocation Arguments",                   -> new CallNode($1, $2)
-  ]
-
-  # The list of arguments to a function invocation.
-  Arguments: [
-    o "CALL_START ArgList CALL_END",            -> $2
-  ]
-
-  # Calling super.
-  Super: [
-    o "SUPER CALL_START ArgList CALL_END",      -> new CallNode('super', $3)
-  ]
-
-  # This references, either naked or to a property.
-  This: [
-    o "@",                                      -> new ValueNode(new LiteralNode('this'))
-    o "@ Identifier",                           -> new ValueNode(new LiteralNode('this'), [new AccessorNode($2)])
-  ]
-
-  # The range literal.
-  Range: [
-    o "[ Expression . . Expression ]",          -> new RangeNode($2, $5)
-    o "[ Expression . . . Expression ]",        -> new RangeNode($2, $6, true)
-  ]
-
-  # The slice literal.
-  Slice: [
-    o "INDEX_START Expression . . Expression INDEX_END", -> new RangeNode($2, $5)
-    o "INDEX_START Expression . . . Expression INDEX_END", -> new RangeNode($2, $6, true)
-  ]
-
-  # The array literal.
-  Array: [
-    o "[ ArgList ]",                            -> new ArrayNode($2)
-  ]
-
-  # A list of arguments to a method call, or as the contents of an array.
-  ArgList: [
-    o "",                                       -> []
-    o "Expression",                             -> [$1]
-    o "INDENT Expression",                      -> [$2]
-    o "ArgList , Expression",                   -> $1.concat [$3]
-    o "ArgList TERMINATOR Expression",          -> $1.concat [$3]
-    o "ArgList , TERMINATOR Expression",        -> $1.concat [$4]
-    o "ArgList , INDENT Expression",            -> $1.concat [$4]
-    o "ArgList OUTDENT",                        -> $1
-  ]
-
-  # Just simple, comma-separated, required arguments (no fancy syntax).
-  SimpleArgs: [
-    o "Expression",                             -> $1
-    o "SimpleArgs , Expression",                ->
-      if $1 instanceof Array then $1.concat([$3]) else [$1].concat([$3])
-  ]
-
-  # Try/catch/finally exception handling blocks.
-  Try: [
-    o "TRY Block Catch",                        -> new TryNode($2, $3[0], $3[1])
-    o "TRY Block FINALLY Block",                -> new TryNode($2, null, null, $4)
-    o "TRY Block Catch FINALLY Block",          -> new TryNode($2, $3[0], $3[1], $5)
-  ]
-
-  # A catch clause.
-  Catch: [
-    o "CATCH Identifier Block",                 -> [$2, $3]
-  ]
-
-  # Throw an exception.
-  Throw: [
-    o "THROW Expression",                       -> new ThrowNode($2)
-  ]
-
-  # Parenthetical expressions.
-  Parenthetical: [
-    o "( Expression )",                         -> new ParentheticalNode($2)
-  ]
-
-  # The condition for a while loop.
-  WhileSource: [
-    o "WHILE Expression",                       -> new WhileNode($2)
-    o "WHILE Expression WHEN Expression",       -> new WhileNode($2, {filter : $4})
-  ]
-
-  # The while loop. (there is no do..while).
-  While: [
-    o "WhileSource Block",                      -> $1.add_body $2
-    o "Expression WhileSource",                 -> $2.add_body $1
-  ]
-
-  # Array comprehensions, including guard and current index.
-  # Looks a little confusing, check nodes.rb for the arguments to ForNode.
-  For: [
-    o "Expression FOR ForVariables ForSource",  -> new ForNode($1, $4, $3[0], $3[1])
-    o "FOR ForVariables ForSource Block",       -> new ForNode($4, $3, $2[0], $2[1])
-  ]
-
-  # An array comprehension has variables for the current element and index.
-  ForVariables: [
-    o "Identifier",                             -> [$1]
-    o "Identifier , Identifier",                -> [$1, $3]
-  ]
-
-  # The source of the array comprehension can optionally be filtered.
-  ForSource: [
-    o "IN Expression",                          -> {source:   $2}
-    o "OF Expression",                          -> {source:   $2, object: true}
-    o "ForSource WHEN Expression",              -> $1.filter: $3; $1
-    o "ForSource BY Expression",                -> $1.step:   $3; $1
-  ]
-
-  # Switch/When blocks.
-  Switch: [
-    o "SWITCH Expression INDENT Whens OUTDENT", -> $4.rewrite_condition($2)
-    o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.rewrite_condition($2).add_else($6, true)
-  ]
-
-  # The inner list of whens.
-  Whens: [
-    o "When",                                   -> $1
-    o "Whens When",                             -> $1.push $2
-  ]
-
-  # An individual when.
-  When: [
-    o "LEADING_WHEN SimpleArgs Block",          -> new IfNode($2, $3, null, {statement: true})
-    o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> new IfNode($2, $3, null, {statement: true})
-    o "Comment TERMINATOR When",                -> $3.comment: $1; $3
-  ]
-
-  # The most basic form of "if".
-  IfStart: [
-    o "IF Expression Block",                    -> new IfNode($2, $3)
-    o "IfStart ElsIfs",                         -> $1.add_else($2)
-  ]
-
-  IfBlock: [
-    o "IfStart",                                -> $1
-    o "IfStart ELSE Block",                     -> $1.add_else($3)
-  ]
-
-  # Multiple elsifs can be chained together.
-  ElsIfs: [
-    o "ELSE IF Expression Block",               -> (new IfNode($3, $4)).force_statement()
-    o "ElsIfs ElsIf",                           -> $1.add_else($2)
-  ]
-
-  # The full complement of if blocks, including postfix one-liner ifs and unlesses.
-  If: [
-    o "IfBlock",                                -> $1
-    o "Expression IF Expression",               -> new IfNode($3, Expressions.wrap([$1]), null, {statement: true})
-    o "Expression UNLESS Expression",           -> new IfNode($3, Expressions.wrap([$1]), null, {statement: true, invert: true})
-  ]
-
+# Wrapping Up
+# -----------
+
+# Finally, now what we have our **grammar** and our **operators**, we can create
+# our **Jison.Parser**. We do this by processing all of our rules, recording all
+# terminals (every symbol which does not appear as the name of a rule above)
+# as "tokens".
+tokens: []
+for name, alternatives of grammar
+  grammar[name]: for alt in alternatives
+    for token in alt[0].split ' '
+      tokens.push token unless grammar[token]
+    alt[1] = "return ${alt[1]}" if name is 'Root'
+    alt
+
+# Initialize the **Parser** with our list of terminal **tokens**, our **grammar**
+# rules, and the name of the root. Reverse the operators because Jison orders
+# precedence from low to high, and we have it high to low
+# (as in [Yacc](http://dinosaur.compilertools.net/yacc/index.html)).
+exports.parser: new Parser {
+  tokens:       tokens.join ' '
+  bnf:          grammar
+  operators:    operators.reverse()
+  startSymbol:  'Root'
 }
-
-# Helpers ==============================================================
-
-# Make the Jison parser.
-bnf: {}
-tokens: []
-for name, non_terminal of grammar
-  bnf[name]: for option in non_terminal
-    for part in option[0].split(" ")
-      if !grammar[part]
-        tokens.push(part)
-    if name == "Root"
-      option[1] = "return ${option[1]}"
-    option
-tokens: tokens.join(" ")
-exports.parser: new Parser({tokens: tokens, bnf: bnf, operators: operators.reverse(), startSymbol: 'Root'}, {debug: false})


Fix #3671: Allow step in optimized range comprehensions

Allow the `by c` part in `for [a..b] by c then`.

Continue disallowing a `when d` part, since it makes no sense having a guard
that isn't given access to anything that changes on every iteration.

--- grammar.coffee
+++ grammar.coffee
@@ -451,7 +451,8 @@
   ]

   ForBody: [
-    o 'FOR Range',                              -> source: LOC(2) new Value($2)
+    o 'FOR Range',                              -> source: (LOC(2) new Value($2))
+    o 'FOR Range BY Expression',                -> source: (LOC(2) new Value($2)), step: $4
     o 'ForStart ForSource',                     -> $2.own = $1.own; $2.name = $1[0]; $2.index = $1[1]; $2
   ]


Issue #706 -- enchancing empty anonymous classes.

--- grammar.coffee
+++ grammar.coffee
@@ -281,6 +281,9 @@
     o "CLASS SimpleAssignable INDENT ClassBody OUTDENT", -> new ClassNode $2, null, $4
     o "CLASS SimpleAssignable EXTENDS Value INDENT ClassBody OUTDENT", -> new ClassNode $2, $4, $6
     o "CLASS INDENT ClassBody OUTDENT",         -> new ClassNode '__temp__', null, $3
+    o "CLASS",                                  -> new ClassNode '__temp__', null, new Expressions
+    o "CLASS EXTENDS Value",                    -> new ClassNode '__temp__', $3, new Expressions
+    o "CLASS EXTENDS Value INDENT ClassBody OUTDENT", -> new ClassNode '__temp__', $3, $5
   ]

   # Assignments that can happen directly inside a class declaration.


ListView: playground

ListView: playground

--- playground/main.coffee
+++ playground/main.coffee
@@ -1,9 +1,29 @@

-# Let's create a simple view
-view = new KDView
-  cssClass : "sample-view"
-  partial  : "It works!"
+class ListItem extends KDListItemView
+
+  partial : ->
+
+    {randomIndex, id} = @getData()
+    "#{id} numarali itemim ulan indexim de #{randomIndex or 'yok'}!!"
+
+
+mainView = new KDView
+KDView.appendToDOMBody mainView
+
+listController = new KDListViewController
+  boxed : yes
+  itemClass : ListItem
+
+
+id = 0
+mainView.addSubView new KDButtonView
+  title    : 'Random indexli eleman ekle'
+  callback : ->
+    if listController.itemsOrdered.length > 3
+      randomIndex = KD.utils.getRandomNumber listController.itemsOrdered.length
+    listController.addItem {title : Date.now(), id : ++id, randomIndex}, randomIndex
+
+mainView.addSubView listController.getView()

 # And append it to DOM
-KDView.appendToDOMBody view


prompting

prompting

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -1,10 +1,15 @@
 @Editor = class Editor
+	promptMessage: 'Type your article here'
 	status:
 		cmd: false
 		ctrl: false
 		alt: false
 		shift: false
 		empty: false
+	displayPrompt: ->
+		$('#editor').html "#{promptMessage}
"
+	hidePrompt: ->
+		$('#editor').html '

'
 	selection: ->
 		window.getSelection() if window.getSelection
 	saveSelection: ->


remove log

remove log

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -1,6 +1,5 @@
 $(document).ready ->
 	update = ->
-		console.log '123'
 		$('#debug').text $('#editor').html()

 	# init


Assign empty array if empty events_ids

Assign empty array if empty events_ids

--- app/assets/javascripts/species/controllers/elibrary_search_controller.js.coffee
+++ app/assets/javascripts/species/controllers/elibrary_search_controller.js.coffee
@@ -19,7 +19,7 @@
       filtersHash.title_query = null
     @set('titleQuery', filtersHash.title_query)
     @set('selectedEventType', @get('controllers.events.eventTypes').findBy('id', filtersHash.event_type))
-    @set('selectedEventsIds', filtersHash.events_ids)
+    @set('selectedEventsIds', filtersHash.events_ids || [])
     allDocumentTypes = @get('controllers.events.documentTypes').concat @get('controllers.events.interSessionalDocumentTypes')
     @set('selectedDocumentType', allDocumentTypes.findBy('id', filtersHash.document_type))
     @set('selectedProposalOutcomeId', filtersHash.proposal_outcome_id)


Updating help text

Updating help text

--- scripts/awesome.team.coffee
+++ scripts/awesome.team.coffee
@@ -9,10 +9,10 @@
 #   List the boards - Lists the available boards for the team (requires a team be set for the channel)
 #   Make {boardname} our board - Associates the requested board with the current channel (requires a team be set for the channel)
 #   What's our board? - Provides the name of the board associated with the channel (requires a team be set for the channel)
-#   What's our current/target/awesome state? - Provides the description for the requested state (requires a team and board be set for the channel)
-#   Set our current/target/awesome state to {description} - Sets the description for the requested state (requires a team and board be set for the channel)
+#   What's our {current/target/awesome} state? - Provides the description for the requested state (requires a team and board be set for the channel)
+#   Set our {current/target/awesome} state to {description} - Sets the description for the requested state (requires a team and board be set for the channel)
 #   What are our achievements? - Lists the achievements on the board (requires a team and board be set for the channel)
-#   @{awesomebotname} Awesome! {achievement} - Adds the provided achievement to the board (requires a team and board be set for the channel, must be addressing the bot to avoid accidental achievement creation)
+#   hubot Awesome! {achievement} - Adds the provided achievement to the board (requires a team and board be set for the channel, must be addressing the bot to avoid accidental achievement creation)

 module.exports = (robot) ->


remove commented out test

remove commented out test

--- test/home/home-controller-spec.coffee
+++ test/home/home-controller-spec.coffee
@@ -49,39 +49,6 @@
         @rootScope.$digest()
         expect(@sut.message).to.deep.equal @message

-    xdescribe 'when the user triggers as a trigger (pew, pew)', ->
-      beforeEach ->
-        @trigger =
-          flow : 1,
-          uuid : 2,
-          token : 3,
-          name : 'Siamese'
-        @triggerService =
-          getTriggers: sinon.stub().returns(@getTriggers.promise),
-          trigger: sinon.stub().returns(@triggerPromise)
-
-        @sut = @controller('HomeController', {
-          TriggerService : @triggerService,
-          $cookies: {uuid: 1, token: 2},
-          $location: @location
-        })
-        @sut.triggerTheTrigger @trigger
-
-      it 'should call TriggerService.trigger with the flowId, flow uuid, user uuid, and user token', ->
-        @rootScope.$digest()
-        expect(@triggerService.trigger).to.have.been.calledWith @trigger.flow, @trigger.uuid, 1, 2
-
-      it 'should add a triggering property to the trigger', ->
-        expect(@trigger.triggering).to.exist
-
-      describe 'when TriggerService.getTriggers resolves with some triggers', ->
-        beforeEach ->
-          @triggerPromise.resolve true
-          @sut.triggerTheTrigger @trigger
-        it 'should remove the triggering property on the trigger', ->
-          @rootScope.$digest()
-          expect(@trigger.triggering).to.not.exist
-
     describe 'when triggerService.getTriggers rejects the promise', ->
       beforeEach ->
         @error = 'ERROR WILL ROBINSON ERROR'


some changes in sending email method

some changes in sending email method

--- app/server/methods.coffee
+++ app/server/methods.coffee
@@ -10,19 +10,23 @@
     check doc, schemas.Invitation
     @unblock()
     doc.emails.forEach (item) =>
-      # TODO #4: It would be good make it in a bit more asynchronous way ;)
-      # TODO #4: We could add callback into the insert function.
-      # TODO #4: In this callback we should send email if there wasn't errors.
-      invitationId = Invitations.insert
-        companyId: doc.companyId
-        message: doc.message or ""
-        emails: [item]
-      Email.send
-        to: item
-        # TODO #3: Make this option configurable as well.
-        from: 'stepan_ua@i.ua'
-        subject: 'Invitation to ' + doc.companyId
-        text: "#{Meteor.absoluteUrl()}invite/#{invitationId}"
+      Invitations.insert {
+          companyId: doc.companyId
+          message: doc.message or ""
+          emails: [item]
+        }, (err, res) ->
+              if err
+                console.log err
+              else
+                Email.send
+                  to: item
+                # TODO #3: Make this option configurable as well.
+                  from: 'invitations@project-x.com'
+                  subject: 'Invitation to ' + doc.companyId
+                  text: """You were invited to company (there is will be company name in future)\n
+                        Please follow this link #{Meteor.absoluteUrl()}invite/#{res} to accept invitation.\n
+                        If you don't want to accept this invitation, just ignore it!.\n
+                        Please, do not reply on this message!"""

   invitationStatus: (id) ->
     check id, String


something not commited?

something not commited?

--- app/server/methods.coffee
+++ app/server/methods.coffee
@@ -23,7 +23,7 @@
             $set:
                 tag: tag

-    validTag: (tag) ->
+    tagIsValid: (tag) ->
         Meteor.users.findOne(tag: tag) of Cases.findOne(tag: tag) or Families.findOne(tag: tag)

     #


新チャンネル日本語化に対応？

新チャンネル日本語化に対応？

--- scripts/notification.coffee
+++ scripts/notification.coffee
@@ -10,7 +10,7 @@
     switch message.type
       when 'channel_created'
         creator = robot.adapter.client.rtm.dataStore.getUserById(message.channel.creator)
-        robot.send {room: "C0P4MNTT8"}, "新しいチャンネルができたよ！ (##{message.channel.name}) By #{creator.real_name}"
+        robot.send {room: "C0P4MNTT8"}, "新しいチャンネルができたよ！ ( ##{message.channel.name} ) By #{creator.real_name}"
       when 'emoji_changed'
         break unless message.subtype is 'add'
         robot.send {room: "C0P4MNTT8"}, "新しい絵文字か追加されたよ!\n どんなの? -> :#{message.name}: [#{message.name}]"


Remove unnecessary brackets.

Remove unnecessary brackets.

--- index.coffee
+++ index.coffee
@@ -52,11 +52,10 @@
     defaultCommand = 'x-terminal-emulator'

 module.exports =
-  config: {
+  config:
     command:
       type: 'string'
       default: defaultCommand
-  },
   activate: ->
     atom.commands.add '.tree-view .selected, atom-text-editor, atom-workspace',
       'open-terminal-here:open': (event) ->


Terminate load task when package is deactivated

--- index.coffee
+++ index.coffee
@@ -15,8 +15,12 @@
     @loadAll()
     @rootView.on 'editor:attached', (e, editor) => @enableSnippetsInEditor(editor)

+  deactivate: ->
+    @loadSnippetsTask?.terminate()
+
   loadAll: ->
-    new LoadSnippetsTask(this).start()
+    @loadSnippetsTask = new LoadSnippetsTask(this)
+    @loadSnippetsTask.start()

   loadDirectory: (snippetsDirPath) ->
     for snippetsPath in fs.list(snippetsDirPath) when fs.base(snippetsPath).indexOf('.') isnt 0


whoos, bad git

whoos, bad git

--- index.coffee
+++ index.coffee
@@ -113,7 +113,7 @@
 	 					else
 	 						user = existingUser[0]
 	 						user.logged_out_at = Date.now()
-
+
 	 						user.save () ->
 	 							pubnub.publish
 				                   channel: user.identifier


Remove outdated comment

Remove outdated comment

--- index.coffee
+++ index.coffee
@@ -1,8 +1,3 @@
-# This is the Hubot Loading Bay.  NPM uses it as an entry point.
-#
-#     Hubot = require 'hubot'
-#     YourBot = Hubot.robot 'campfire', 'yourbot'
-
 exports.loadBot = (adapterPath, adapterName, enableHttpd, botName) ->
   robot = require './src/robot'
   new robot adapterPath, adapterName, enableHttpd, botName


Override the SyntaxError's "stack" property instead of deleting it

This makes the "stack" property more useful when it's shown on other Node.js applications that compile CoffeeScript (e.g. testing libraries) and should fix #3023. A minimal example:

    $ node -e 'require("coffee-script").compile("class class")'

    /usr/lib/node_modules/coffee-script/lib/coffee-script/coffee-script.js:41
            throw err;
                  ^
    [stdin]:1:7: error: unexpected CLASS
    class class
          ^^^^^

--- helpers.coffee
+++ helpers.coffee
@@ -143,8 +143,10 @@
   error.location = location
   error.toString = syntaxErrorToString

-  # Prevent compiler error from showing the compiler's stacktrace.
-  delete error.stack
+  # Instead of showing the compiler's stacktrace, show our custom error message
+  # (this is useful when the error bubbles up in Node.js applications that
+  # compile CoffeeScript for example).
+  Object.defineProperty? error, 'stack', get: -> @toString()

   throw error


airlibre

airlibre

--- client/channels.coffee
+++ client/channels.coffee
@@ -28,5 +28,7 @@
     'fip': { url: 'http://mp3.live.tv-radio.com/fip/all/fiphautdebit.mp3' }
     'tsfjazz': { url: 'http://tsfjazz.ice.infomaniak.ch:80/tsfjazz-high', tags: ['ads'] }

+    'radioairlibre': { url: 'http://streaming.domainepublic.net:8000/radioairlibre.ogg', tags: ['libre'] }
+
     # '106fmcoil': 'http://212.29.254.129:7075/'
 }


remove debug stuff

remove debug stuff

--- client/comments.coffee
+++ client/comments.coffee
@@ -67,7 +67,6 @@
 update_callback = (error, result) ->
   if error?
     console.error error
-  console.log "result", result

 on_delete_comment_callback = (error) ->
   if error?
@@ -75,8 +74,6 @@

 Template.show_comments.events
   "click .delete": (evt, tmpl) ->
-    console.log "clicked delete"
-
     # Need to do this on server because Collection2 (buggily)
     # auto-updates .time and .userId fields in our {$pull: {comments:
     # {comment: "comment text"}}} dict and thereby causes the match to


Edits made to javascript to make sure we get the right form divs for different options.

--- app/assets/javascripts/incident_reports/edit.coffee
+++ app/assets/javascripts/incident_reports/edit.coffee
@@ -58,10 +58,30 @@
   if reason.includes('Reasonable Suspicion')
     $('.post-accident-info').slideUp()
     $('.reasonable-suspicion-info').slideDown()
+    $('.driver-discounted-info').slideUp()
+    $('.fta-threshold-info').slideUp()
+
   else if reason.includes('Threshold met (completed drug test)')
+    $('.driver-discounted-info').slideUp()
     $('.reasonable-suspicion-info').slideUp()
+    $('.fta-threshold-info').slideUp()
     $('.post-accident-info').slideDown()
+
+  else if reason.includes('No threshold met')
+    $('.driver-discounted-info').slideUp()
+    $('.fta-threshold-info').slideDown()
+    $('.post-accident-info').slideUp()
+    $('.reasonable-suspicion-info').slideUp()
+
+  else if reason.includes('discounted')
+    $('.driver-discounted-info').slideDown()
+    $('.fta-threshold-info').slideUp()
+    $('.post-accident-info').slideUp()
+    $('.reasonable-suspicion-info').slideUp()
+
   else
+    $('.driver-discounted-info').slideUp()
+    $('.fta-threshold-info').slideUp()
     $('.post-accident-info').slideUp()
     $('.reasonable-suspicion-info').slideUp()


fix(perf): Add makerCluster on map for performance reason

--- app/assets/javascripts/modules/map_module.js.coffee
+++ app/assets/javascripts/modules/map_module.js.coffee
@@ -29,7 +29,7 @@
     MM.oneMovieLayer = L.layerGroup()
     defaultLayers.push MM.oneMovieLayer

-    MM.allMovieLayer = new L.FeatureGroup()
+    MM.allMovieLayer = new L.MarkerClusterGroup(maxClusterRadius: 30, disableClusteringAtZoom: 10)
     defaultLayers.push MM.allMovieLayer
     if options && options.movies
       @movies = options.movies


fix "Other (please specify)" answer

fix "Other (please specify)" answer

--- app/assets/javascripts/stores/navigation_store.cjsx
+++ app/assets/javascripts/stores/navigation_store.cjsx
@@ -113,7 +113,7 @@
             QuestionnaireStore.nullAnswer(question.id, false)

   allAnswersForQuestion: (allQuestions, questionId) =>
-    _.chain(allQuestions)
+    allAnswers = _.chain(allQuestions)
       .filter((question, _key) -> question.id == questionId)
       .filter((question, _key) => @isQuestionVisible(question))
       .map((question, _key) -> question.answers)
@@ -121,6 +121,9 @@
       .compact()
       .value()

+    allAnswers.push("other")
+    allAnswers
+
   addPageChangeListener: (callback) => @on(PAGE_CHANGE_EVENT, callback)
   addTabChangeListener:  (callback) => @on(TAB_CHANGE_EVENT,  callback)


remove stray debugger statement from editorAccessibility

test plan:
  - debugger should not run for the removed line when you open the page!

Change-Id: I65f83515e5e6c32770673fb4895bddb5e242abf1
Reviewed-on: https://gerrit.instructure.com/18181
Reviewed-by: James Williams  <3a5f4ed991dbfa5c9ef76ad729d240ca12f62180@instructure.com>
QA-Review: Stanley Stuart <2b43fb8b7a234825d50dd49ce7892d78a59da8f3@instructure.com>
Reviewed-by: Bracken Mosbacker <48b846001bca4166dc3fb7711563afc17525921e@instructure.com>
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>

--- app/coffeescripts/editor/editorAccessibility.coffee
+++ app/coffeescripts/editor/editorAccessibility.coffee
@@ -29,7 +29,6 @@
       @$el.find("##{@id_prepend}_instructure_record_voice").append('<br/>').append(I18n.t('accessibles.record', 'This feature is inaccessible for screen readers.'))
       @$el.find("##{@id_prepend}_instructure_record img").attr('alt',
         @$el.find("##{@id_prepend}_instructure_record img").attr('alt') + ", " + I18n.t('accessibles.record', 'This feature is inaccessible for screen readers.'));
-      debugger

     _addTitles: ->
       @$iframe.attr 'title', I18n.t('titles.rte_help', 'Rich Text Area. Press ALT F10 for toolbar. Press ALT 0 for help.')


wait for core for paragraph buttons

wait for core for paragraph buttons

--- app/js/jail_iframe/classes/paragraph_buttons.coffee
+++ app/js/jail_iframe/classes/paragraph_buttons.coffee
@@ -50,14 +50,15 @@
     $(selector).filter(':visible')

   addParagraphButtons: ->
-    return unless FactlinkJailRoot.can_haz.paragraph_icons
-
     for paragraphButton in @_paragraphButtons
       paragraphButton.destroy()

     @_addParagraphButtonsBatch @_paragraphElements()
     FactlinkJailRoot.perf.add_timing_event 'paragraph buttons added'

-FactlinkJailRoot.host_ready_promise.then ->
-  paragraphButtons = new ParagraphButtons
-  paragraphButtons.addParagraphButtons()
+FactlinkJailRoot.host_ready_promise
+  .then(-> FactlinkJailRoot.core_loaded_promise) #wait due to FactlinkJailRoot.can_haz.paragraph_icons
+  .then ->
+    if  FactlinkJailRoot.can_haz.paragraph_icons
+      paragraphButtons = new ParagraphButtons
+      paragraphButtons.addParagraphButtons()


mocha: Mention difference to mocha-compat

--- src/mocha.coffee
+++ src/mocha.coffee
@@ -1,4 +1,8 @@

+## Run fbp-spec testcases using Mocha as a runner/frontend
+## Intended to allow reuse of Mocha reporters, or
+## to quickly add a couple of fbp-spec cases to a predominantly Mocha-based testsuite
+## See also ./mochacompat.coffee

 Runner = require('./runner').Runner
 testsuite = require './testsuite'


Allow images from any origin

Allow images from any origin

--- server/browserpolicy.coffee
+++ server/browserpolicy.coffee
@@ -3,9 +3,9 @@
 Meteor.startup(->
   BrowserPolicy.content.allowImageOrigin(
     "https://s3-#{Meteor.settings.AWSRegion}.amazonaws.com")
-  BrowserPolicy.content.allowImageOrigin("https://*.githubusercontent.com")
   BrowserPolicy.content.allowImageOrigin("blob:")
-  BrowserPolicy.content.allowImageOrigin("https://*.flattr.com")
+  BrowserPolicy.content.allowImageOrigin("https://*")
+  BrowserPolicy.content.allowImageOrigin("http://*")
   BrowserPolicy.content.allowEval()
   BrowserPolicy.framing.allowAll()
   BrowserPolicy.content.allowFrameOrigin("*.googletagmanager.com")


corrected subscription url scheme

corrected subscription url scheme

--- src/coffee/clients.coffee
+++ src/coffee/clients.coffee
@@ -196,7 +196,7 @@
   windowsPhone: [
     {
       title: 'BringCast'
-      scheme: 'bringcast:'
+      scheme: 'bringcast://subscribe/'
       icon: 'windowsphone/bringcast@2x.png'
       install: 'http://windowsphone.com/s?appId=e5abef38-d413-e011-9264-00237de2db9e'
       http: true


Whoops

Whoops

--- helpers.coffee
+++ helpers.coffee
@@ -1,5 +1,7 @@
 console.success = (message) -> console.info '\x1b[1m', '\x1b[32m', message, '\x1b[39m', '\x1b[22m'
 console.error = (message) -> console.info '\x1b[1m', '\x1b[31m', message, '\x1b[39m', '\x1b[22m'
+
+Function::define = (name, getSet) -> Object.defineProperty @prototype, name, getSet

 @NTRU_def = process.env.NODE_TLS_REJECT_UNAUTHORIZED
 @bound = Meteor.bindEnvironment (callback) -> return callback()


Activity: implement latency compensation for like summary view

--- client/Social/Activity/views/likesummaryview.coffee
+++ client/Social/Activity/views/likesummaryview.coffee
@@ -7,8 +7,9 @@
     super options, data

     data
-      .on "LikeAdded", @bound "updateActors"
+      .on "LikeAdded",   @bound "updateActors"
       .on "LikeRemoved", @bound "updateActors"
+      .on "LikeChanged", @bound "handleLikeChanged"

   showLikers: ->
@@ -27,6 +28,22 @@

         return KD.showError err  if err
         new ShowMoreDataModalView null, accounts
+
+
+  handleLikeChanged: (liked) ->
+
+    {actorsPreview} = @getData().interactions.like
+
+    if liked
+      actorsPreview.unshift KD.whoami()._id
+      @getData().interactions.like.actorsCount += 1
+    else
+      for id, index in actorsPreview when id is KD.whoami()._id
+        actorsPreview.splice index, 1
+        @getData().interactions.like.actorsCount -= 1
+        break
+
+    @updateActors()

   updateActors: ->
@@ -50,9 +67,10 @@
     else
       callback null, []

+
   refresh: (accounts = []) ->

-    return @hide() if accounts.length is 0
+    return @hide()  if accounts.length is 0

     {actorsCount, actorsPreview} = @getData().interactions.like
     actorsCount = Math.max actorsCount, actorsPreview.length
@@ -103,3 +121,4 @@
     super

     @updateActors()
+


Activity: your topics modal made reuseable

--- client/Social/Activity/views/yourtopicsmodal.coffee
+++ client/Social/Activity/views/yourtopicsmodal.coffee
@@ -8,6 +8,9 @@
     options.overlay   ?= yes
     options.width     ?= 330
     options.height   or= 'auto'
+    options.endpoints ?=
+      fetch            : KD.singletons.socialapi.channel.fetchFollowedChannels
+      search           : KD.singletons.socialapi.channel.searchTopics

     super options, data

@@ -56,9 +59,9 @@

     return @fetchForSearch options, callback  if @searchActive

-    {channel} = KD.singletons.socialapi
+    {fetch} = @getOptions().endpoints

-    channel.fetchFollowedChannels options, (err, items = []) =>
+    fetch options, (err, items = []) =>

       @listController.hideLazyLoader()
       @beingFetched = no
@@ -70,12 +73,11 @@

   fetchForSearch: (options = {}, callback) ->

-    {channel} = KD.singletons.socialapi
-
     options.name ?= @searchField.getValue()
     @lastTerm     = options.name

-    channel.searchTopics options, (err, items) =>
+    {search} = @getOptions().endpoints
+    search options, (err, items) =>

       @listController.hideLazyLoader()
       @beingFetched = no


AccountReferralSystemList: tidy up the code

--- client/account/lib/accountreferralsystemlist.coffee
+++ client/account/lib/accountreferralsystemlist.coffee
@@ -1,17 +1,13 @@
-$ = require 'jquery'
-kd = require 'kd'
-KDListView = kd.ListView
+kd                            = require 'kd'
+KDListView                    = kd.ListView
 AccountReferralSystemListItem = require './accountreferralsystemlistitem'

 module.exports = class AccountReferralSystemList extends KDListView

-  constructor:(options,data)->
-    options = $.extend
-      tagName      : "ul"
-      itemClass : AccountReferralSystemListItem
-    ,options
+  constructor: (options = {}, data)->
+
+    options.tagName   ?= 'ul'
+    options.itemClass ?= AccountReferralSystemListItem
+
     super options,data
-
-
-


Prevent Mekko labels from overlapping

Prevent Mekko labels from overlapping


Reverse legend for horizontal orientation

--- client/controllers/events/eventAffectedAreas.coffee
+++ client/controllers/events/eventAffectedAreas.coffee
@@ -180,7 +180,7 @@
 Template.eventAffectedAreas.helpers
   legendValues: ->
     maxCount = Template.instance().maxCount.get()
-    _.range(1, 1 + (maxCount or 0), maxCount / 5).reverse().map (value) ->
+    _.range(1, 1 + (maxCount or 0), maxCount / 5).map (value) ->
       value: value.toFixed(0)
       color: Template.instance().getColor(value / maxCount)


add @govizlora and @gnattu to contributor list

--- assets/data/constant.cson
+++ assets/data/constant.cson
@@ -72,7 +72,7 @@
     avatar: 'https://avatars2.githubusercontent.com/u/1572561?v=3&s=400'
     link: 'https://github.com/Gizeta'
   ,
-    name: 'KagamiChan'
+    name: 'かがみ'
     avatar: 'https://avatars2.githubusercontent.com/u/3816900?v=3&s=400'
     link: 'https://github.com/KagamiChan'
   ,
@@ -83,6 +83,14 @@
     name: 'Javran'
     avatar: 'https://gist.githubusercontent.com/Javran/02ac7ebefc307829d02e5dc942f8ef28/raw/250x250.png'
     link: 'https://github.com/Javran'
+  ,
+    name: 'govizlora'
+    avatar: 'https://avatars2.githubusercontent.com/u/12785565?v=4&s=400'
+    link: 'https://github.com/govizlora'
+  ,
+    name: 'Gnattu'
+    avatar: 'https://avatars0.githubusercontent.com/u/12995396?v=4&s=400'
+    link: 'https://github.com/gnattu'
 ]

 thanksTo: [


Resolves issue with assert's util module dependency.

--- assert.coffee
+++ assert.coffee
@@ -1,2 +1,3 @@
 require.stub "util", require "./util"
+require.stub "util/", require "./util"
 module.exports = require "assert"


Add Perl snippets for GetOptions and "say" feature

--- src/configs/snippets.cson
+++ src/configs/snippets.cson
@@ -268,6 +268,16 @@
 	Dump:
 		prefix: "dump"
 		body: "print Dumper(${1:$data});"
+	"Say: Import":
+		prefix: "say"
+		body: 'use feature "say";'
+	"Getopt: Import":
+		prefix: "opt"
+		body: "use Getopt::Long qw(:config auto_abbrev);"
+	"Getopt: Usage":
+		prefix: "getopt"
+		body: 'GetOptions(${1:"number=i" => $number, "string=s" => $string, "boolean"  => $bool});'
+

 # Ruby
 ".source.ruby":


adds deep component finder to cardview

adds deep component finder to cardview

--- src/core/container.coffee
+++ src/core/container.coffee
@@ -18,6 +18,7 @@

   initialize: (@options={})->
     _.extend @, @options
+    _.bindAll @, "index_components"

     @setupHooks( Luca.core.Container.prototype.hooks )

@@ -42,6 +43,10 @@
     console.log @component_type, "should implement its own prepare components method"

   create_components: ()->
+    map = @component_index =
+      name_index: {}
+      cid_index: {}
+
     @components = _( @components ).map (object, index)=>
       component = if _.isObject( object ) and object.ctype? then Luca.util.LazyObject( object ) else object

@@ -49,9 +54,32 @@
       # with their passed options, so this is a workaround
       if !component.renderTo and component.options.renderTo
         component.container = component.renderTo = component.options.renderTo
+
+      if map and component.cid?
+        map.cid_index[ component.cid ] = index
+
+      if map and component.name?
+        map.name_index[ component.name ] = index

       component

+  findComponentByName: (name, deep=false)-> @findComponent name, "name_index", deep
+
+  findComponentById: (id, deep=false)-> @findComponent id, "cid_index", deep
+
+  findComponent: (needle, haystack="name", deep=false)->
+    position = @component_index[ haystack ][ needle ]
+    component = @components[ position ]
+
+    return component if component
+
+    if deep is true
+      sub_container = _( @components ).detect (component)-> component?.findComponent?(needle, haystack, true)
+      sub_container.findComponent?(needle, haystack, true)
+
+  component_names: ()->
+    _( @component_index.name_index ).keys()
+
   render_components: (@debugMode="")->
     _(@components).each (component)=>
       component.getParent = ()=> @


resurrection.editor: abort preview of filepaths starting with "localfile"

--- client/Ace/aceappview.coffee
+++ client/Ace/aceappview.coffee
@@ -122,6 +122,7 @@

   preview: ->
     {path, vmName} = @getActiveAceView().getData()
+    return  if /^localfile/.test path
     KD.singleton("appManager").create "Viewer", {path, vmName}, (app) =>
       @tabView.addPane new KDTabPaneView
         name    : "[#{path.split("/").last}]"


Tests: Updated comment.

Tests: Updated comment.

--- client/ide/lib/routes.coffee
+++ client/ide/lib/routes.coffee
@@ -214,8 +214,10 @@

 routeHandler = (type, info, state, path, ctx) ->

-  # This is just a dirty workaround to be able to run the unit tests
-  # in the future we hope to find a better way and remove this imports. -- acet /cc usirin
+  # This is just a dirty workaround to be able to run the unit tests because
+  # exported functions are not the same functions as the defined ones,
+  # this is to make spies work in the future we hope to find a better way and
+  # remove this imports. -- acet /cc usirin
   { routeToLatestWorkspace, loadCollaborativeIDE, routeToMachineWorkspace, loadIDE } = module.exports

   switch type


More careful overriding of clicks

More careful overriding of clicks

Just vanilla left clicks on <a> tags

--- client/lib/autoscroll.coffee
+++ client/lib/autoscroll.coffee
@@ -23,6 +23,12 @@
   saveTops()

 $(window).click (e) ->
+  ## Only override clicks on <a> tags
+  return unless e.target?.tagName?.toLowerCase() == 'a'
+  ## Only override left clicks
+  return unless e.button == 0
+  ## Only override vanilla clicks. Inspired by https://github.com/iron-meteor/iron-location/blob/c3ad6663c37d3a94f0929c78f3c3fef8adf84dc9/lib/location.js#L130
+  return if e.metaKey or e.ctrlKey or e.shiftKey
   ## If we click on a link with a hash mark in it, forget and therefore
   ## don't scroll to remembered position.
   if e.target?.href?.endsWith? '#'
@@ -38,7 +44,7 @@
       scrollToMessage e.target.hash
   ## Instantly go to internal paths, bypassing Iron Router
   if e.target?.hostname == window.location.hostname and
-     internalPath.test e.target?.pathname and e.button == 0
+     internalPath.test e.target?.pathname
     e.preventDefault()
     window.location = e.target.href


add missing is_public field definition

add missing is_public field definition

Fixes #36

--- client/skr/models/Sku.coffee
+++ client/skr/models/Sku.coffee
@@ -10,6 +10,7 @@
         default_uom_code:    {type:"string"}
         code:                {type:"code",   required:true}
         description:         {type:"string", required:true}
+        is_public:           {type:"boolean", default:false}
         is_other_charge:     {type:"boolean", default:false}
         does_track_inventory:{type:"boolean", default:false}
         can_backorder:       {type:"boolean", default:false}


Don't block observe for too long.

Don't block observe for too long.

--- server/lib/worker.coffee
+++ server/lib/worker.coffee
@@ -34,15 +34,16 @@
   return if queueRunning
   queueRunning = true

-  while job = JobQueue.Meta.collection.getWork _.keys Job.types
-    try
-      result = new Job.types[job.type](job.data).run()
-    catch error
-      job.fail error
-      continue
-    job.done result
+  Meteor.defer ->
+    while job = JobQueue.Meta.collection.getWork _.keys Job.types
+      try
+        result = new Job.types[job.type](job.data).run()
+      catch error
+        job.fail error
+        continue
+      job.done result

-  queueRunning = false
+    queueRunning = false

 Meteor.startup ->
   # TODO: Use Meteor's logging package for logging


Fix application page link for now

Fix application page link for now

--- client/landing/app/Applications/Apps.kdapplication/Views/AppsListItemView.coffee
+++ client/landing/app/Applications/Apps.kdapplication/Views/AppsListItemView.coffee
@@ -34,33 +34,6 @@
     @setTemplate @pistachio()
     @template.update()

-  #   if @getData().installedA
-  #     @alreadyInstalledText()
-  #   else
-  #     @createInstallButton()
-
-  # createInstallButton:->
-  #   app = @getData()
-
-  #   @installButton.destroy() if @installButton?
-  #   @installButton = new KDButtonView
-  #     title : "Install"
-  #     icon  : no
-  #     callback: =>
-  #       list = @getDelegate()
-  #       list.propagateEvent KDEventType : "AppWantsToExpand", app
-
-  #   @addSubView @installButton, '.button-container'
-
-  # alreadyInstalledText:->
-
-  #   @installButton.destroy() if @installButton?
-  #   @installButton = new KDButtonView
-  #     title     : "Installed"
-  #     icon      : no
-  #     disabled  : yes
-  #   @addSubView @installButton, '.button-container'
-
   pistachio:->
     """

@@ -82,6 +55,6 @@

{a[href="#"]{#(title)}}

{{@utils.shortenText #(body)}}

-      Application Page →
+      Application Page →

     """


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com


Return boolean

Return boolean


Pull off the `is-done` class when transitioning out; flatten pyramid for fun

--- components/zig_zag_banner/index.coffee
+++ components/zig_zag_banner/index.coffee
@@ -47,35 +47,34 @@
     existingMargin = parseInt(@$el.css 'marginTop')
     offset = @$target.outerHeight() / 2
     newMargin = offset + existingMargin
+    @$el.css marginTop: newMargin

-    @$el.css marginTop: newMargin
+  sequence: (arr) ->
+    _.map arr, (fn, i) =>
+      dfd = $.Deferred()
+      _.delay =>
+        dfd.resolve fn()
+      , (@segmentTransitionLength * (i + 1))
+      dfd.promise()

   transitionIn: ->
     @render()
     _.defer =>
-      @$one.addClass 'is-in'
-      _.delay =>
-        @$two.addClass 'is-in'
-        _.delay =>
-          @$three.addClass 'is-in'
-          _.delay =>
-            @$el.addClass 'is-done'
-          , @segmentTransitionLength
-        , @segmentTransitionLength
-      , @segmentTransitionLength
+      @sequence [
+        => @$one.addClass 'is-in'
+        => @$two.addClass 'is-in'
+        => @$three.addClass 'is-in'
+        => @$el.addClass 'is-done'
+      ]

   transitionOut: ->
     dfd = $.Deferred()
-    @$three.removeClass 'is-in'
-    _.delay =>
-      @$two.removeClass 'is-in'
-      _.delay =>
-        @$one.removeClass 'is-in'
-        _.delay =>
-          dfd.resolve()
-        , @segmentTransitionLength
-      , @segmentTransitionLength
-    , @segmentTransitionLength
+    @sequence([
+      => @$el.removeClass 'is-done'
+      => @$three.removeClass 'is-in'
+      => @$two.removeClass 'is-in'
+      => @$one.removeClass 'is-in'
+    ]).then dfd.resolve
     dfd.promise()

   close: (e) ->


Don’t use Serializable mixin in DisplayBuffer

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -1,5 +1,4 @@
 _ = require 'underscore-plus'
-Serializable = require 'serializable'
 {CompositeDisposable, Emitter} = require 'event-kit'
 {Point, Range} = require 'text-buffer'
 TokenizedBuffer = require './tokenized-buffer'
@@ -17,8 +16,6 @@

 module.exports =
 class DisplayBuffer extends Model
-  Serializable.includeInto(this)
-
   verticalScrollMargin: 2
   horizontalScrollMargin: 6
   scopedCharacterWidthsChangeCount: 0
@@ -34,6 +31,10 @@
   scrollWidth: 0
   verticalScrollbarWidth: 15
   horizontalScrollbarHeight: 15
+
+  @deserialize: (state) ->
+    state.tokenizedBuffer = TokenizedBuffer.deserialize(state.tokenizedBuffer)
+    new this(state)

   constructor: ({tabLength, @editorWidthInChars, @tokenizedBuffer, buffer, ignoreInvisibles, @largeFileMode}={}) ->
     super
@@ -93,7 +94,8 @@

     @updateWrappedScreenLines() if oldConfigSettings? and not _.isEqual(oldConfigSettings, @configSettings)

-  serializeParams: ->
+  serialize: ->
+    deserializer: 'DisplayBuffer'
     id: @id
     softWrapped: @isSoftWrapped()
     editorWidthInChars: @editorWidthInChars
@@ -101,10 +103,6 @@
     scrollLeft: @scrollLeft
     tokenizedBuffer: @tokenizedBuffer.serialize()
     largeFileMode: @largeFileMode
-
-  deserializeParams: (params) ->
-    params.tokenizedBuffer = TokenizedBuffer.deserialize(params.tokenizedBuffer)
-    params

   copy: ->
     newDisplayBuffer = new DisplayBuffer({@buffer, tabLength: @getTabLength(), @largeFileMode})


Rename method to indicate functionality

Rename method to indicate functionality