`}` closes math + renamed {} scope to meta

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -44,6 +44,8 @@
       { include: '#makeatsomething' }
       { include: '#verbatim' }
       { include: '#item' }
+      { include: '#displayMathMode'}
+      { include: '#inlineMathMode' }
       { include: '#texPrimitives' }
       { include: '#controlSymbol' }
       { include: '#controlWord' }
@@ -74,15 +76,15 @@
     match: '&'
   }
   openCurlyBracketMeta: {
-    contentName: 'variable.parameter.argument.latex'
+    contentName: 'meta.group.braces.latex'
     begin: '{'
     beginCaptures:
       0:
-        name: 'punctuation.definition.argument.latex'
+        name: 'punctuation.definition.group.latex'
     end: '}'
     endCaptures:
       0:
-        name: 'punctuation.definition.argument.latex'
+        name: 'punctuation.definition.group.latex'
     patterns: [
       comment: 'Optimisation good to implement here. Rework commentMeta to be a more general check for escaped characters and comments'
       {
@@ -363,7 +365,7 @@
     beginCaptures:
       0:
         name: 'string.other.math.inline.begin.latex'
-    end: '(\\$)|(\\\\\\))'
+    end: '(\\$)|(\\\\\\))|(?=\\})'
     endCaptures:
       0:
         name: 'string.other.math.inline.end.latex'
@@ -391,7 +393,7 @@
         name: 'string.other.math.display.begin.latex'
       1:
         name: 'invalid.deprecated.latex'
-    end: '(\\$\\$)|(\\\\\\])'
+    end: '(\\$\\$)|(\\\\\\])|(?=\\})'
     endCaptures:
       0:
         name: 'string.other.math.display.end.latex'


Add elements from current language-stata package

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -120,7 +120,13 @@
   {
     'comment': 'keywords that delimit flow conditionals'
     'name': 'keyword.control.conditional.stata'
-    'match': '\\b(if|else)\\b'
+    'match': '\\b(if|else if|else)\\b'
+  }
+  {
+    'captures':
+      '1':
+        'name': 'storage.type.scalar.stata'
+    'match': '^\\s*(sca(l|la|lar)?(\\s+de(f|fi|fin|fine)?)?)\\s+(?!(drop|dir?|l(i|is|ist)?)\\s+)'
   }
   {
     'captures':
@@ -144,13 +150,8 @@
   }
   {
     'comment': 'keywords that delimit loops'
-    'name': 'keyword.control.repeat.stata'
-    'match': '\\b(while)\\b'
-  }
-  {
-    'comment': 'keywords that alter flow from within a block'
-    'name': 'keyword.control.statement.stata'
-    'match': '\\b(continue)\\b'
+    'name': 'keyword.control.flow.stata'
+    'match': '\\b(while|continue)\\b'
   }
   {
     'captures':
@@ -170,7 +171,7 @@
   'match': '\\b(qui(e|et|etl|etly)?|n(o|oi|ois|oisi|oisil|oisily)?|cap(t|tu|tur|ture)?)\\b:?'
   }
   {
-    'match': '\\s*(program)\\s+((de(f|fi|fin|fine)?|di(r)?|drop|l(i|is|ist)?)?\\s+)?([A-Za-z_][A-Za-z0-9_]{0,31})'
+    'match': '\\s*(pr(o|og|ogr|ogra|ogram)?)\\s+((de(f|fi|fin|fine)?|di(r)?|drop|l(i|is|ist)?)?\\s+)?([A-Za-z_][A-Za-z0-9_]{0,31})'
     'captures':
       '1':
         'name': 'storage.type.function.stata'
@@ -185,17 +186,36 @@
       '1': 'keyword.functions.data.stata.test'
   }
   {
+    "captures":
+      "1":
+        "name": "support.function.models.stata"
+    "comment": "model commands."
+    "match": "\\b(anova|xtmixed|regress|ivregress|xtreg|xtreg_be|xtreg_fe|xtreg_ml|xtreg_pa_p|xtreg_re|xtregar|xtrere_p|xtset|xtsf_ll|xtsf_llti|xtsum|xttab|xttest0|xttobit|xttobit_8|xttobit_p|xttrans)\\b"
+  }
+
+  # Start manual functions:
+  {
     'captures':
       '1':
         'name': 'keyword.functions.data.stata'
-    'comment': 'miscellaneous to deal with later',
-    'match': '\\b(sa(v|ve)|saveold|destring|tostring|note(s)?|format)\\b'
-  }
-  # Start manual functions:
-  # Prefixes:
-  # # prefix commands: by (bysort) statsby rolling bootstrap jackknife permute simulate svy "mi estimate" nestreg stepwise xi fp mfp capture noisily quietly version
-  {
-    'match': '\\b(g(e|en|ene|erer|enera|enerat|enerate)?)\\s+((byte|int|long|float|double|str[1-9]?[0-9]?[0-9]?[0-9]?|strL)?\\s+)?([A-Za-z_][A-Za-z0-9_]{0,31})'
+    'comment': 'one-word commands',
+    'match': '\\b(sa(v|ve)|saveold|destring|replace|tostring|u(s|se)?|note(s)?|form(a|at)?)\\b'
+  }
+  {
+    'match': '\\b(exit|end)\\b'
+    'name': 'keyword.functions.data.stata'
+    'comment': 'programming commands'
+  }
+  {
+    'match': '\\b(g(e|en|ene|erer|enera|enerat|enerate)?|egen)\\s+((byte|int|long|float|double|str[1-9]?[0-9]?[0-9]?[0-9]?|strL)?\\s+)?([A-Za-z_][A-Za-z0-9_]{0,31})'
+    'captures':
+      '1':
+        'name': 'keyword.functions.data.stata'
+      '3':
+        'name': 'support.type.stata'
+  }
+  {
+    'match': '\\b(set ty(p|pe)?)\\s+((byte|int|long|float|double|str[1-9]?[0-9]?[0-9]?[0-9]?|strL)?\\s+)'
     'captures':
       '1':
         'name': 'keyword.functions.data.stata'
@@ -240,7 +260,19 @@
         'name': 'keyword.functions.data.stata'
       '10':
         'name': 'keyword.functions.data.stata'
-  }
+  }
+  {
+    'begin': '^\\s*mata:?\\s*$'
+    'comment': 'won\'t match single-line Mata statements'
+    'contentName': 'source.mata'
+    'end': '^\\s*end\\s*$\\n?'
+    'name': 'meta.embedded.block.mata'
+    'patterns': [
+      {
+        'include': 'source.mata'
+      }
+    ]
+  }
 ]
 'repository':
   'builtin_functions':
@@ -284,6 +316,14 @@
   'builtin_variables':
     'match': '\\b(_b|_coef|_cons|_n|_N|_rc|_se)\\b'
     'name': 'variable.object.stata'
+  'commands-other':
+    'patterns': [
+      {
+        'comment': 'generic keywords that alter flow. Without disctintion. We can separate this after, but now they will be colored'
+        'match': '\\b(about|ac|ac_7|acprplot|acprplot_7|adjust|ado|adopath|adoupdate|alpha|ameans|an|ano|anov|anova|anova_estat|anova_terms|anovadef|aorder|ap|app|appe|appen|append|arch|arch_dr|arch_estat|arch_p|archlm|areg|areg_p|args|arima|arima_dr|arima_estat|arima_p|asmprobit|asmprobit_estat|asmprobit_lf|asmprobit_mfx__dlg|asmprobit_p|avplot|avplot_7|avplots|avplots_7|bcskew0|bgodfrey|binreg|bip0_lf|biplot|bipp_lf|bipr_lf|bipr_p|biprobit|bitest|bitesti|bitowt|blogit|bmemsize|boot|bootsamp|bootstrap_8|boxco_l|boxco_p|boxcox|boxcox_6|boxcox_p|bprobit|br|break|brier|bro|brow|brows|browse|brr|brrstat|bs|bs_7|bsampl_w|bsample|bsample_7|bsqreg|bstat|bstat_7|bstat_8|bstrap|bstrap_7|ca|ca_estat|ca_p|cabiplot|camat|canon|canon_8|canon_8_p|canon_estat|canon_p|caprojection|cat|cc|cchart|cchart_7|cci|cd|censobs_table|centile|cf|char|chdir|checkdlgfiles|checkestimationsample|checkhlpfiles|checksum|chelp|ci|cii|cl|class|classutil|clear|cli|clis|clist|clo|clog|clog_lf|clog_p|clogi|clogi_sw|clogit|clogit_lf|clogit_p|clogitp|clogl_sw|cloglog|clonevar|clslistarray|cluster|cluster_measures|cluster_stop|cluster_tree|cluster_tree_8|clustermat|cmdlog|cnr|cnre|cnreg|cnreg_p|cnreg_sw|cnsreg|codebook|collaps4|collapse|colormult_nb|colormult_nw|compare|compress|conf|confi|confir|confirm|conren|cons|const|constr|constra|constrai|constrain|constraint|contract|copy|copyright|copysource|cor|corc|corr|corr2data|corr_anti|corr_kmo|corr_smc|corre|correl|correla|correlat|correlate|corrgram|cou|coun|count|cox|cox_p|cox_sw|coxbase|coxhaz|coxvar|cprplot|cprplot_7|crc|cret|cretu|cretur|creturn|cross|cs|cscript|cscript_log|csi|ct|ct_is|ctset|ctst_5|ctst_st|cttost|cumsp|cumsp_7|cumul|cusum|cusum_7|cutil|d|datasig|datasign|datasigna|datasignat|datasignatu|datasignatur|datasignature|datetof|db|dbeta|de|dec|deco|decod|decode|deff|des|desc|descr|descri|describ|describe|dfbeta|dfgls|dfuller|di|di_g|dir|dirstats|dis|discard|disp|disp_res|disp_s|displ|displa|display|do|doe|doed|doedi|doedit|dotplot|dotplot_7|dprobit|drawnorm|ds|ds_util|dstdize|duplicates|durbina|dwstat|dydx|e|ed|edi|edit|egen|eivreg|emdef|en|enc|enco|encod|encode|eq|erase|ereg|ereg_lf|ereg_p|ereg_sw|ereghet|ereghet_glf|ereghet_glf_sh|ereghet_gp|ereghet_ilf|ereghet_ilf_sh|ereghet_ip|eret|eretu|eretur|ereturn|err|erro|error|est|est_cfexist|est_cfname|est_clickable|est_expand|est_hold|est_table|est_unhold|est_unholdok|estat|estat_default|estat_summ|estat_vce_only|esti|estimates|etodow|etof|etomdy|expand|expandcl|fac|fact|facto|factor|factor_estat|factor_p|factor_pca_rotated|factor_rotate|factormat|fcast|fcast_compute|fcast_graph|fdades|fdadesc|fdadescr|fdadescri|fdadescrib|fdadescribe|fdasav|fdasave|fdause|fh_st|file|filefilter|fillin|find_hlp_file|findfile|findit|findit_7|fit|fl|fli|flis|flist|for5_0|fpredict|frac_154|frac_adj|frac_chk|frac_cox|frac_ddp|frac_dis|frac_dv|frac_in|frac_mun|frac_pp|frac_pq|frac_pv|frac_wgt|frac_xo|fracgen|fracplot|fracplot_7|fracpoly|fracpred|fron_ex|fron_hn|fron_p|fron_tn|fron_tn2|frontier|ftodate|ftoe|ftomdy|ftowdate|g|gamhet_glf|gamhet_gp|gamhet_ilf|gamhet_ip|gamma|gamma_d2|gamma_p|gamma_sw|gammahet|gdi_hexagon|gdi_spokes|genrank|genstd|genvmean|gettoken|gladder|gladder_7|glim_l01|glim_l02|glim_l03|glim_l04|glim_l05|glim_l06|glim_l07|glim_l08|glim_l09|glim_l10|glim_l11|glim_l12|glim_lf|glim_mu|glim_nw1|glim_nw2|glim_nw3|glim_p|glim_v1|glim_v2|glim_v3|glim_v4|glim_v5|glim_v6|glim_v7|glm|glm_6|glm_p|glm_sw|glmpred|glogit|glogit_8|glogit_p|gmeans|gnbre_lf|gnbreg|gnbreg_5|gnbreg_p|gomp_lf|gompe_sw|gomper_p|gompertz|gompertzhet|gomphet_glf|gomphet_glf_sh|gomphet_gp|gomphet_ilf|gomphet_ilf_sh|gomphet_ip|gphdot|gphpen|gphprint|gprefs|gprobi_p|gprobit|gprobit_8|gr|gr7|gr_copy|gr_current|gr_db|gr_describe|gr_dir|gr_draw|gr_draw_replay|gr_drop|gr_edit|gr_editviewopts|gr_example|gr_example2|gr_export|gr_print|gr_qscheme|gr_query|gr_read|gr_rename|gr_replay|gr_save|gr_set|gr_setscheme|gr_table|gr_undo|gr_use|graph|graph7|grebar|greigen|greigen_7|greigen_8|grmeanby|grmeanby_7|gs_fileinfo|gs_filetype|gs_graphinfo|gs_stat|gsort|gwood|h|hadimvo|hareg|hausman|haver|he|heck_d2|heckma_p|heckman|heckp_lf|heckpr_p|heckprob|hel|help|hereg|hetpr_lf|hetpr_p|hetprob|hettest|hexdump|hilite|hist|hist_7|histogram|hlogit|hlu|hmeans|hotel|hotelling|hprobit|hreg|hsearch|icd9|icd9_ff|icd9p|iis|impute|imtest|inbase|include|inf|infi|infil|infile|infix|inp|inpu|input|ins|insheet|insp|inspe|inspec|inspect|integ|inten|intreg|intreg_7|intreg_p|intrg2_ll|intrg_ll|intrg_ll2|ipolate|iqreg|ir|irf|irf_create|irfm|iri|is_svy|is_svysum|isid|istdize|ivprob_1_lf|ivprob_lf|ivprobit|ivprobit_p|ivreg|ivreg_footnote|ivtob_1_lf|ivtob_lf|ivtobit|ivtobit_p|jacknife|jknife|jknife_6|jknife_8|jkstat|joinby|kalarma1|kap|kap_3|kapmeier|kappa|kapwgt|kdensity|kdensity_7|ksm|ksmirnov|ktau|kwallis|labelbook|ladder|levels|levelsof|leverage|lfit|lfit_p|li|lincom|line|linktest|lis|list|lloghet_glf|lloghet_glf_sh|lloghet_gp|lloghet_ilf|lloghet_ilf_sh|lloghet_ip|llogi_sw|llogis_p|llogist|llogistic|llogistichet|lnorm_lf|lnorm_sw|lnorma_p|lnormal|lnormalhet|lnormhet_glf|lnormhet_glf_sh|lnormhet_gp|lnormhet_ilf|lnormhet_ilf_sh|lnormhet_ip|lnskew0|loadingplot|log|logi|logis_lf|logistic|logistic_p|logit|logit_estat|logit_p|loglogs|logrank|loneway|lookfor|lookup|lowess|lowess_7|lpredict|lrecomp|lroc|lroc_7|lrtest|ls|lsens|lsens_7|lsens_x|lstat|ltable|ltable_7|ltriang|lv|lvr2plot|lvr2plot_7|m|ma|mac|macr|macro|makecns|man|manova|manova_estat|manova_p|manovatest|mantel|mark|markin|markout|marksample|mat|mat_capp|mat_order|mat_put_rr|mat_rapp|mata|mata_clear|mata_describe|mata_drop|mata_matdescribe|mata_matsave|mata_matuse|mata_memory|mata_mlib|mata_mosave|mata_rename|mata_which|matalabel|matcproc|matlist|matname|matr|matri|matrix|matrix_input__dlg|matstrik|mcc|mcci|md0_|md1_|md1debug_|md2_|md2debug_|mds|mds_estat|mds_p|mdsconfig|mdslong|mdsmat|mdsshepard|mdytoe|mdytof|me_derd|mean|means|median|memory|memsize|meqparse|mer|merg|merge|mfp|mfx|mhelp|mhodds|minbound|mixed_ll|mixed_ll_reparm|mkassert|mkdir|mkmat|mkspline|ml|ml_5|ml_adjs|ml_bhhhs|ml_c_d|ml_check|ml_clear|ml_cnt|ml_debug|ml_defd|ml_e0|ml_e0_bfgs|ml_e0_cycle|ml_e0_dfp|ml_e0i|ml_e1|ml_e1_bfgs|ml_e1_bhhh|ml_e1_cycle|ml_e1_dfp|ml_e2|ml_e2_cycle|ml_ebfg0|ml_ebfr0|ml_ebfr1|ml_ebh0q|ml_ebhh0|ml_ebhr0|ml_ebr0i|ml_ecr0i|ml_edfp0|ml_edfr0|ml_edfr1|ml_edr0i|ml_eds|ml_eer0i|ml_egr0i|ml_elf|ml_elf_bfgs|ml_elf_bhhh|ml_elf_cycle|ml_elf_dfp|ml_elfi|ml_elfs|ml_enr0i|ml_enrr0|ml_erdu0|ml_erdu0_bfgs|ml_erdu0_bhhh|ml_erdu0_bhhhq|ml_erdu0_cycle|ml_erdu0_dfp|ml_erdu0_nrbfgs|ml_exde|ml_footnote|ml_geqnr|ml_grad0|ml_graph|ml_hbhhh|ml_hd0|ml_hold|ml_init|ml_inv|ml_log|ml_max|ml_mlout|ml_mlout_8|ml_model|ml_nb0|ml_opt|ml_p|ml_plot|ml_query|ml_rdgrd|ml_repor|ml_s_e|ml_score|ml_searc|ml_technique|ml_unhold|mleval|mlf_|mlmatbysum|mlmatsum|mlog|mlogi|mlogit|mlogit_footnote|mlogit_p|mlopts|mlsum|mlvecsum|mnl0_|mor|more|mov|move|mprobit|mprobit_lf|mprobit_p|mrdu0_|mrdu1_|mvdecode|mvencode|mvreg|mvreg_estat|nbreg|nbreg_al|nbreg_lf|nbreg_p|nbreg_sw|nestreg|net|newey|newey_7|newey_p|news|nl|nl_7|nl_9|nl_9_p|nl_p|nl_p_7|nlcom|nlcom_p|nlexp2|nlexp2_7|nlexp2a|nlexp2a_7|nlexp3|nlexp3_7|nlgom3|nlgom3_7|nlgom4|nlgom4_7|nlinit|nllog3|nllog3_7|nllog4|nllog4_7|nlog_rd|nlogit|nlogit_p|nlogitgen|nlogittree|nlpred|nobreak|notes_dlg|nptrend|numlabel|numlist|odbc|old_ver|olo|olog|ologi|ologi_sw|ologit|ologit_p|ologitp|on|one|onew|onewa|oneway|op_colnm|op_comp|op_diff|op_inv|op_str|opr|opro|oprob|oprob_sw|oprobi|oprobi_p|oprobit|oprobitp|opts_exclusive|order|orthog|orthpoly|ou|out|outf|outfi|outfil|outfile|outs|outsh|outshe|outshee|outsheet|ovtest|pac|pac_7|palette|parse|parse_dissim|pause|pca|pca_8|pca_display|pca_estat|pca_p|pca_rotate|pcamat|pchart|pchart_7|pchi|pchi_7|pcorr|pctile|pentium|pergram|pergram_7|permute_8|personal|peto_st|pkcollapse|pkcross|pkequiv|pkexamine|pkexamine_7|pkshape|pksumm|pksumm_7|pl|plo|plot|plugin|pnorm|pnorm_7|poisgof|poiss_lf|poiss_sw|poisso_p|poisson|poisson_estat|post|postclose|postfile|postutil|pperron|prais|prais_e|prais_e2|prais_p|predict|predictnl|preserve|print|prob|probi|probit|probit_estat|probit_p|proc_time|procoverlay|procrustes|procrustes_estat|procrustes_p|profiler|prop|proportion|prtest|prtesti|pwcorr|pwd|q\s|qby|qbys|qchi|qchi_7|qladder|qladder_7|qnorm|qnorm_7|qqplot|qqplot_7|qreg|qreg_c|qreg_p|qreg_sw|qu|quadchk|quantile|quantile_7|que|quer|query|range|ranksum|ratio|rchart|rchart_7|rcof|recast|recode|reg|reg3|reg3_p|regdw|regr|regre|regre_p2|regres|regres_p|regress|regress_estat|regriv_p|remap|ren|rena|renam|rename|renpfix|repeat|reshape|restore|ret|retu|retur|return|rmdir|robvar|roccomp|roccomp_7|roccomp_8|rocf_lf|rocfit|rocfit_8|rocgold|rocplot|rocplot_7|roctab|roctab_7|rologit|rologit_p|rot|rota|rotat|rotate|rotatemat|rreg|rreg_p|ru|run|runtest|rvfplot|rvfplot_7|rvpplot|rvpplot_7|safesum|sample|sampsi|savedresults|sc|scatter|scm_mine|sco|scob_lf|scob_p|scobi_sw|scobit|scor|score|scoreplot|scoreplot_help|scree|screeplot|screeplot_help|sdtest|sdtesti|se|search|separate|seperate|serrbar|serrbar_7|serset|set|set_defaults|sfrancia|sh|she|shel|shell|shewhart|shewhart_7|signestimationsample|signrank|signtest|simul|simul_7|simulate_8|sktest|sleep|slogit|slogit_d2|slogit_p|smooth|snapspan|so|sor|sort|spearman|spikeplot|spikeplot_7|spikeplt|spline_x|split|sqreg|sqreg_p|sret|sretu|sretur|sreturn|ssc|st|st_ct|st_hc|st_hcd|st_hcd_sh|st_is|st_issys|st_note|st_promo|st_set|st_show|st_smpl|st_subid|stack|statsby_8|stbase|stci|stci_7|stcox|stcox_estat|stcox_fr|stcox_fr_ll|stcox_p|stcox_sw|stcoxkm|stcoxkm_7|stcstat|stcurv|stcurve|stcurve_7|stdes|stem|stepwise|stereg|stfill|stgen|stir|stjoin|stmc|stmh|stphplot|stphplot_7|stphtest|stphtest_7|stptime|strate|strate_7|streg|streg_sw|streset|sts|sts_7|stset|stsplit|stsum|sttocc|sttoct|stvary|stweib|su|suest|suest_8|sum|summ|summa|summar|summari|summariz|summarize|sunflower|sureg|survcurv|survsum|svar|svar_p|svmat|svy_disp|svy_dreg|svy_est|svy_est_7|svy_estat|svy_get|svy_gnbreg_p|svy_head|svy_header|svy_heckman_p|svy_heckprob_p|svy_intreg_p|svy_ivreg_p|svy_logistic_p|svy_logit_p|svy_mlogit_p|svy_nbreg_p|svy_ologit_p|svy_oprobit_p|svy_poisson_p|svy_probit_p|svy_regress_p|svy_sub|svy_sub_7|svy_x|svy_x_7|svy_x_p|svydes|svydes_8|svygen|svygnbreg|svyheckman|svyheckprob|svyintreg|svyintreg_7|svyintrg|svyivreg|svylc|svylog_p|svylogit|svymarkout|svymarkout_8|svymean|svymlog|svymlogit|svynbreg|svyolog|svyologit|svyoprob|svyoprobit|svyopts|svypois|svypois_7|svypoisson|svyprobit|svyprobt|svyprop|svyprop_7|svyratio|svyreg|svyreg_p|svyregress|svyset|svyset_7|svyset_8|svytab|svytab_7|svytest|svytotal|sw|sw_8|swcnreg|swcox|swereg|swilk|swlogis|swlogit|swologit|swoprbt|swpois|swprobit|swqreg|swtobit|swweib|symmetry|symmi|symplot|symplot_7|syntax|sysdescribe|sysdir|sysuse|szroeter|ta|tab|tab1|tab2|tab_or|tabd|tabdi|tabdis|tabdisp|tabi|table|tabodds|tabodds_7|tabstat|tabu|tabul|tabula|tabulat|tabulate|te|tes|test|testnl|testparm|teststd|tetrachoric|time_it|timer|tis|tob|tobi|tobit|tobit_p|tobit_sw|token|tokeni|tokeniz|tokenize|total|translate|translator|transmap|treat_ll|treatr_p|treatreg|trim|trnb_cons|trnb_mean|trpoiss_d2|trunc_ll|truncr_p|truncreg|tsappend|tset|tsfill|tsline|tsline_ex|tsreport|tsrevar|tsrline|tsset|tssmooth|tsunab|ttest|ttesti|tut_chk|tut_wait|tutorial|tw|tware_st|two|twoway|twoway__fpfit_serset|twoway__function_gen|twoway__histogram_gen|twoway__ipoint_serset|twoway__ipoints_serset|twoway__kdensity_gen|twoway__lfit_serset|twoway__normgen_gen|twoway__pci_serset|twoway__qfit_serset|twoway__scatteri_serset|twoway__sunflower_gen|twoway_ksm_serset|ty|typ|type|typeof|unab|unabbrev|unabcmd|update|uselabel|var|var_mkcompanion|var_p|varbasic|varfcast|vargranger|varirf|varirf_add|varirf_cgraph|varirf_create|varirf_ctable|varirf_describe|varirf_dir|varirf_drop|varirf_erase|varirf_graph|varirf_ograph|varirf_rename|varirf_set|varirf_table|varlmar|varnorm|varsoc|varstable|varstable_w|varstable_w2|varwle|vce|vec|vec_fevd|vec_mkphi|vec_p|vec_p_w|vecirf_create|veclmar|veclmar_w|vecnorm|vecnorm_w|vecrank|vecstable|verinst|vers|versi|versio|version|view|viewsource|vif|vwls|wdatetof|webdescribe|webseek|webuse|weib1_lf|weib2_lf|weib_lf|weib_lf0|weibhet_glf|weibhet_glf_sh|weibhet_glfa|weibhet_glfa_sh|weibhet_gp|weibhet_ilf|weibhet_ilf_sh|weibhet_ilfa|weibhet_ilfa_sh|weibhet_ip|weibu_sw|weibul_p|weibull|weibull_c|weibull_s|weibullhet|wh|whelp|whi|which|wilc_st|wilcoxon|win|wind|windo|window|winexec|wntestb|wntestb_7|wntestq|xchart|xchart_7|xcorr|xcorr_7|xi|xi_6|xmlsav|xmlsave|xmluse|xpose|xsh|xshe|xshel|xshell|xt_iis|xt_tis|xtab_p|xtabond|xtbin_p|xtclog|xtcloglog|xtcloglog_8|xtcloglog_d2|xtcloglog_pa_p|xtcloglog_re_p|xtcnt_p|xtcorr|xtdata|xtdes|xtfront_p|xtfrontier|xtgee|xtgee_elink|xtgee_estat|xtgee_makeivar|xtgee_p|xtgee_plink|xtgls|xtgls_p|xthaus|xthausman|xtht_p|xthtaylor|xtile|xtint_p|xtintreg|xtintreg_8|xtintreg_d2|xtintreg_p|xtivp_1|xtivp_2|xtivreg|xtline|xtline_ex|xtlogit|xtlogit_8|xtlogit_d2|xtlogit_fe_p|xtlogit_pa_p|xtlogit_re_p|xtmixed|xtmixed_estat|xtmixed_p|xtnb_fe|xtnb_lf|xtnbreg|xtnbreg_pa_p|xtnbreg_refe_p|xtpcse|xtpcse_p|xtpois|xtpoisson|xtpoisson_d2|xtpoisson_pa_p|xtpoisson_refe_p|xtpred|xtprobit|xtprobit_8|xtprobit_d2|xtprobit_re_p|xtps_fe|xtps_lf|xtps_ren|xtps_ren_8|xtrar_p|xtrc|xtrc_p|xtrchh|xtrefe_p|yx|yxview__barlike_draw|yxview_area_draw|yxview_bar_draw|yxview_dot_draw|yxview_dropline_draw|yxview_function_draw|yxview_iarrow_draw|yxview_ilabels_draw|yxview_normal_draw|yxview_pcarrow_draw|yxview_pcbarrow_draw|yxview_pccapsym_draw|yxview_pcscatter_draw|yxview_pcspike_draw|yxview_rarea_draw|yxview_rbar_draw|yxview_rbarm_draw|yxview_rcap_draw|yxview_rcapsym_draw|yxview_rconnected_draw|yxview_rline_draw|yxview_rscatter_draw|yxview_rspike_draw|yxview_spike_draw|yxview_sunflower_draw|zap_s|zinb|zinb_llf|zinb_plf|zip|zip_llf|zip_p|zip_plf|zt_ct_5|zt_hc_5|zt_hcd_5|zt_is_5|zt_iss_5|zt_sho_5|zt_smp_5|ztbase_5|ztcox_5|ztdes_5|ztereg_5|ztfill_5|ztgen_5|ztir_5|ztjoin_5|ztnb|ztnb_p|ztp|ztp_p|zts_5|ztset_5|ztspli_5|ztsum_5|zttoct_5|ztvary_5|ztweib_5|prtab|prchange|eststo|estout|esttab|estadd|estpost)\\b'
+        'name': 'keyword.control.flow.stata'
+      }
+    ]
   'comments':
     'patterns': [
       {
@@ -484,7 +524,7 @@
       'match': '[A-Za-z_][A-Za-z0-9_]{0,31}'
   'illegal_names':
       'match':
-       '\\bgen(e|er|era|erat|erate)?\\s((byte|int|long|float|double|str[1-9]?[0-9]?[0-9]?[0-9]?|strL)?\\s)?(_all|_b|byte|_coef|_cons|double|float|if|in|int|long|_n|_N|_pi|_pred|_rc|_skip|str[0-9]+|strL|using|with|[0-9][A-Za-z0-9_]+|[A-Za-z_][A-Za-z0-9_]{32,})\\b\\s*(///)?\\s*\\n?\\s*='
+       '\\b(gen(e|er|era|erat|erate)?|egen)\\s((byte|int|long|float|double|str[1-9]?[0-9]?[0-9]?[0-9]?|strL)?\\s)?(_all|_b|byte|_coef|_cons|double|float|if|in|int|long|_n|_N|_pi|_pred|_rc|_skip|str[0-9]+|strL|using|with|[0-9][A-Za-z0-9_]+|[A-Za-z_][A-Za-z0-9_]{32,})\\b\\s*(///)?\\s*\\n?\\s*='
       'name': 'invalid.illegal.name.stata'
       'comment': 'highlights as illegal if variable name is more than 32 characters'
   'varlist':


minor comment

minor comment

--- fizzylogo_Objects.coffee
+++ fizzylogo_Objects.coffee
@@ -103,6 +103,8 @@
            # right-associativity, depending on just the first token.
            # For example, "^" and "^ -" should be lumped together, and same for
            # all assignment methods all starting with "="
+           # (although we get right-associativity for "=" by just leaving its
+           # precedence to null for the time being)
            eachSignature.firstElement().flToString() != previousSignature.firstElement().flToString()
             goodMatchSoFar = false


Update master

Update master

--- src/ui-message-queue.coffee
+++ src/ui-message-queue.coffee
@@ -16,9 +16,9 @@
   messagesCount : 0
   useMessageBox : true

-  #default vars
-  timeOut : 1000 #timeout value to display message
-  emptyDisplayString : "..." #default string to display when no messages in queue
+  #default atrributes
+  timeOut : 1000 # timeout value to display message
+  emptyDisplayString : "..." # default string to display when no messages in queue

   # constructor taking arguments
   constructor: (args) ->
@@ -26,28 +26,36 @@
     @clear()

     if args
+
       @setAttributes args
       #show initial message
       @dispMsg @emptyDisplayString
+
     else
+
       throw "Missing arguments. UiMessageQueue requires arguments to run."

   # method to set attributes from args passed
   setAttributes: (attrs)->

-      # Optional div id
+      # Set optional div id
       if attrs.message_box_div_id
+
         messageBoxId = attrs.message_box_div_id

-      # Assign optional values
+      # Test and assign timeout
       if attrs.timeout_val
         #test if timeout_val is numeric
         if isFinite attrs.timeout_val
+
           @timeOut = attrs.timeout_val
+
         else
+
           throw "Invalid argument: timeout_val is not numeric"

       if attrs.empty_display_str
+
         @emptyDisplayString = attrs.empty_display_str

       # Try and find the El by ID
@@ -57,6 +65,7 @@
           #Found ok so set to var instead of searching each time
           @useMessageBox = true
           @messageBoxDivEl = document.getElementById(messageBoxId)
+
         else
           # Unable to find El so fall back to alert message
           @useMessageBox = false
@@ -67,10 +76,12 @@

       return

-  # cleardown obj, reset count and queue
+  # cleardown, reset count and queue
   clear: =>
+
     @messagesCount = 0
     @messagesArr = []
+

   # Add a message to the queue
   push: ( message ) =>
@@ -80,7 +91,9 @@

       # if the queue has messages then just add to the end
       if @messagesArr.length > 0
+
         @messagesArr.push message
+
       else
         #else add and call display timer
         @messagesArr.push message
@@ -93,9 +106,11 @@

   # Method to display message
   dispMsg: (val) =>
+
     if @useMessageBox == true
       @messageBoxDivEl.innerHTML = val
-
+
+
   # Timeout method to work through queue
   updateMsgBox: =>
     self = @
@@ -112,7 +127,7 @@
       self.dispMsg self.messagesArr[self.messagesCount]
       self.messagesCount++

-      # pass obj ref to timeout func and call with timeOut value
+      # pass obj ref to timeout call and call with timeOut value
       setTimeout ((self) ->
         self.updateMsgBox()
       ), self.timeOut, this


Sort query path by worst-case execution speed

--- src/underscore-query.coffee
+++ src/underscore-query.coffee
@@ -15,8 +15,8 @@
 # We assign local references to the underscore methods used.
 # If underscore is not supplied we use the above ES5 methods
 createUtils = (_) ->
-  for key in ["every", "some", "filter", "first", "find", "reject", "reduce", "property",
-      "intersection", "isEqual", "keys", "isArray", "result", "map", "includes", "isNaN"]
+  for key in ["every", "some", "filter", "first", "find", "reject", "reduce", "property", "sortBy"
+      "indexOf", "intersection", "isEqual", "keys", "isArray", "result", "map", "includes", "isNaN"]
     utils[key] = _[key]
     throw new Error("#{key} missing. Please ensure that you first initialize
       underscore-query with either lodash or underscore") unless utils[key]
@@ -135,6 +135,18 @@
   # Return the query object
   return result

+# Order in which to sort tags in order to optimize speed. Tags at the start of this array
+# are ones which can be evaluated quickly in order to avoid running the slower tags
+tag_sort_order = [
+  "$lt", "$lte", "$gt", "$gte",
+  "$exists", "$has", "$type", "$ne", "$equal",
+  "$mod", "$size", "$between", "$betweene",
+  "$startsWith", "$endsWith", "$like", "$likeI",
+  "$cb", "$regex", "$regexp",
+  "$contains", "$in", "$nin", "$all", "$any",
+  "$deepEqual", "$elemMatch",
+  "$not", "$and", "$or", "$nor"
+]

 # This function parses and normalizes raw queries.
 parseSubQuery = (rawQuery, type) ->
@@ -153,7 +165,12 @@
       memo.concat parsed

   # Loop through all the different queries
-  utils.reduce(queryArray, iteratee, [])
+  result = utils.reduce(queryArray, iteratee, [])
+  # Attempt to optimize the query path
+  utils.sortBy(result, (x) ->
+    index = utils.indexOf(tag_sort_order, x.type)
+    if index >= 0 then index else Infinity
+  )

 # Tests query value, to ensure that it is of the correct type
 testQueryValue = (queryType, value) ->
@@ -194,25 +211,25 @@
       # If the attribute is an array then search for the query value in the array the same as Mongo
       if utils.isArray(attr) then utils.includes(attr, value) else (attr is value)
     when "$deepEqual"       then utils.isEqual(attr, value)
-    when "$contains"        then utils.includes(attr, value)
     when "$ne"              then attr isnt value
+    when "$type"            then typeof attr is value
     when "$lt"              then value? and attr < value
     when "$gt"              then value? and attr > value
     when "$lte"             then value? and attr <= value
     when "$gte"             then value? and attr >= value
     when "$between"         then value[0]? and value[1]? and value[0] < attr < value[1]
     when "$betweene"        then value[0]? and value[1]? and value[0] <= attr <= value[1]
+    when "$size"            then attr.length is value
+    when "$exists", "$has"  then attr? is value
+    when "$contains"        then utils.includes(attr, value)
     when "$in"              then utils.includes(value, attr)
     when "$nin"             then not utils.includes(value, attr)
     when "$all"             then utils.every value, (item) -> utils.includes(attr, item)
     when "$any"             then utils.some attr, (item) -> utils.includes(value, item)
-    when "$size"            then attr.length is value
-    when "$exists", "$has"  then attr? is value
     when "$like"            then attr.indexOf(value) isnt -1
     when "$likeI"           then attr.toLowerCase().indexOf(value) isnt -1
     when "$startsWith"      then attr.toLowerCase().indexOf(value) is 0
     when "$endsWith"        then utils.reverseString(attr).indexOf(value) is 0
-    when "$type"            then typeof attr is value
     when "$regex", "$regexp" then value.test attr
     when "$mod"             then (attr % value[0]) is value[1]
     else false


Add process.noAsar to turn off asar support

--- atom/common/lib/asar.coffee
+++ atom/common/lib/asar.coffee
@@ -18,6 +18,7 @@

 # Separate asar package's path from full path.
 splitPath = (p) ->
+  return [false] if process.noAsar  # shortcut to disable asar.
   return [false] if typeof p isnt 'string'
   return [true, p, ''] if p.substr(-5) is '.asar'
   p = path.normalize p


Take out the string parsing so that it's not run on every request

--- guts/routing.coffee
+++ guts/routing.coffee
@@ -30,6 +30,16 @@
                         # Split the routes on a space so as to separate individual action handlers.
                         allRoutes = actionString.split ' '

+                        # Loop through all the actions that are provided for that route,
+                        # look them up, return back the handles on the function.
+                        #
+                        # So as to save a "push" command we'll use a map
+                        actionHandles = _.map allRoutes, (a) ->
+                                actionComponent = a.split '.'
+                                myController = actionComponent[0]
+                                myAction = actionComponent[1]
+                                return controllerObject[myController][myAction]
+
                         wrapper = (req, res) ->
                                         # A quick holder for all the promises yet to come.
                                         promiseArray = []
@@ -41,16 +51,6 @@

                                         # Push this promise into our promise array.
                                         promiseArray.push tempPromise
-
-                                        # Loop through all the actions that are provided for that route,
-                                        # look them up, return back the handles on the function.
-                                        #
-                                        # So as to save a "push" command we'll use a map
-                                        actionHandles = _.map allRoutes, (a) ->
-                                                actionComponent = a.split '.'
-                                                myController = actionComponent[0]
-                                                myAction = actionComponent[1]
-                                                return controllerObject[myController][myAction]

                                         # Once we've gotten all the handles on the functions we need
                                         # to call, we can concat it to all previous promises. Afterwards


Added dyno files

Added dyno files

--- app/routes.coffee
+++ app/routes.coffee
@@ -9,10 +9,14 @@
 # Assets files.
 assetsDir = path.join __dirname, 'assets'
 indexFile = path.join __dirname, 'assets', 'html' ,'index.html'
+dynoFile = path.resolve __dirname, '..', 'wakemydyno.txt'

 # App config.
 router.use '/assets', express.static(assetsDir)
 router.use '/api', api
+
+router.use '/wakemydyno.txt', (req, res) ->
+  res.sendFile dynoFile

 # Send main html file.
 router.get '*', (req, res) ->


Delete additional suffixes

Delete additional suffixes

--- resources/assets/coffee/osu_common.coffee
+++ resources/assets/coffee/osu_common.coffee
@@ -214,7 +214,7 @@

   formatNumberSuffixed: (number, precision, options = {}) ->
-    suffixes = ['', 'k', 'm', 'b', 't', 'qa', 'qi', 'sx', 'sp', 'oc', 'no']
+    suffixes = ['', 'k', 'm', 'b', 't']
     k = 1000

     format = (n) ->


Add more specific initialization test

Add more specific initialization test

--- test/node/initialization.coffee
+++ test/node/initialization.coffee
@@ -18,6 +18,7 @@
       caman = Caman(greyPath)
       assert.isObject caman
       assert.isFunction caman.render
+      assert.instanceOf caman, Caman

   describe "with two arguments", ->
     it "accepts a file path and a callback", ->


Adding Slot to highlighting

Adding Slot to highlighting

--- grammars/mathematica.cson
+++ grammars/mathematica.cson
@@ -14,6 +14,11 @@
     'comment': 'Integers'
     'match': '\\b[0-9]+',
     'name': 'constant.integer'
+  }
+  {
+    'comment': 'Slot'
+    'match': "#\\d*",
+    'name': 'keyword.operator'
   }
   {
     'comment': 'Constant'


* replace the __getter__/__setter__ to defineProperty

--- src/Object.coffee
+++ src/Object.coffee
@@ -2,10 +2,10 @@
 inherits          = require("inherits-ex/lib/inherits")
 createObject      = require("inherits-ex/lib/createObject")
 createObjectWith  = require("inherits-ex/lib/createObjectWith")
-isArray           = require("./util/isArray")
-isFunction        = require("./util/isFunction")
-isUndefined       = require("./util/isUndefined")
-
+isArray           = require("util-ex/lib/is/type/array")
+isFunction        = require("util-ex/lib/is/type/function")
+isUndefined       = require("util-ex/lib/is/type/undefined")
+defineProperty    = require("util-ex/lib/defineProperty")

 # AbstractObject with Object State Events Supports.
 # class should overwrite the init, final methods.
@@ -34,11 +34,10 @@
 module.exports = class AbstractObject
   inherits AbstractObject, EventEmitter
   OBJECT_STATES: OBJECT_STATES
-  @::__defineGetter__ "Class", ->
-    return @__proto__.constructor
-  @.prototype.__defineGetter__ "objectState", ->
-    vState = @_objectState_
-    if not vState? then "destroyed" else OBJECT_STATES_STR[vState]
+  defineProperty @::, "objectState", null,
+    get:->
+      vState = @_objectState_
+      if not vState? then "destroyed" else OBJECT_STATES_STR[vState]
   for vStateName, vState of OBJECT_STATES
     s = 'is'+ vStateName[0].toUpperCase() + vStateName.slice(1)
     @::[s] = ((aState)->
@@ -70,6 +69,7 @@
       @final.apply @, arguments
   constructor: ->
     #@setObjectState "initing"
+    defineProperty @, '_objectState_', null
     @changeObjectState OBJECT_STATES.initing
     @setMaxListeners(Infinity)
     if @initialize.apply(@, arguments) isnt true


turn off docblockr tag if appears directly after word character i.e. turns off highlighting for an email address.

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -729,13 +729,13 @@
   'docblockr-comment':
     'patterns': [
       {
-        'match': '(@(error|ERROR))\\b'
+        'match': '(?<!\\w)(@(error|ERROR))\\b'
         'captures':
           '1':
             'name': 'invalid.illegal.name.stata'
       }
       {
-        'match': '(@[A-za-z0-9]+)\\b'
+        'match': '(?<!\\w)(@[A-za-z0-9]+)\\b'
         'captures':
           '1':
             'name': 'keyword.docblockr.stata'


Semi colons

Semi colons

--- test/tests/TextLayerTest.coffee
+++ test/tests/TextLayerTest.coffee
@@ -531,35 +531,35 @@

 	describe "Fonts", ->
 		it "should infer fontWeight from design", ->
-			text = new TextLayer({ "name": "text", "backgroundColor": null, "width": 162, "x": 107, "styledText": { "blocks": [{ "inlineStyles": [{ "startIndex": 0, "endIndex": 4, "css": { "fontSize": "80px", "WebkitTextFillColor": "rgb(0, 0, 0)", "whiteSpace": "pre", "letterSpacing": "0px", "lineHeight": "1.2", "tabSize": 4, "fontFamily": "\".SFNSDisplay-Heavy\", \"SFProDisplay-Heavy\", \"SFUIDisplay-Heavy\", \".SFUIDisplay-Heavy\", sans-serif" } }], "text": "Test" }] }, "height": 96, "constraintValues": { "left": null, "height": 96, "centerAnchorX": 0.5013333333333333, "width": 162, "top": null, "centerAnchorY": 0.50074962518740629 }, "blending": "normal", "autoSize": true, "y": 286 });
+			text = new TextLayer({ "name": "text", "backgroundColor": null, "width": 162, "x": 107, "styledText": { "blocks": [{ "inlineStyles": [{ "startIndex": 0, "endIndex": 4, "css": { "fontSize": "80px", "WebkitTextFillColor": "rgb(0, 0, 0)", "whiteSpace": "pre", "letterSpacing": "0px", "lineHeight": "1.2", "tabSize": 4, "fontFamily": "\".SFNSDisplay-Heavy\", \"SFProDisplay-Heavy\", \"SFUIDisplay-Heavy\", \".SFUIDisplay-Heavy\", sans-serif" } }], "text": "Test" }] }, "height": 96, "constraintValues": { "left": null, "height": 96, "centerAnchorX": 0.5013333333333333, "width": 162, "top": null, "centerAnchorY": 0.50074962518740629 }, "blending": "normal", "autoSize": true, "y": 286 })
 			text.fontWeight.should.equal 800

 		it "should infer fontFamily from design", ->
-			text = new TextLayer({ "name": "text", "backgroundColor": null, "width": 162, "x": 107, "styledText": { "blocks": [{ "inlineStyles": [{ "startIndex": 0, "endIndex": 4, "css": { "fontSize": "80px", "WebkitTextFillColor": "rgb(0, 0, 0)", "whiteSpace": "pre", "letterSpacing": "0px", "lineHeight": "1.2", "tabSize": 4, "fontFamily": "\".SFNSDisplay-Heavy\", \"SFProDisplay-Heavy\", \"SFUIDisplay-Heavy\", \".SFUIDisplay-Heavy\", sans-serif" } }], "text": "Test" }] }, "height": 96, "constraintValues": { "left": null, "height": 96, "centerAnchorX": 0.5013333333333333, "width": 162, "top": null, "centerAnchorY": 0.50074962518740629 }, "blending": "normal", "autoSize": true, "y": 286 });
+			text = new TextLayer({ "name": "text", "backgroundColor": null, "width": 162, "x": 107, "styledText": { "blocks": [{ "inlineStyles": [{ "startIndex": 0, "endIndex": 4, "css": { "fontSize": "80px", "WebkitTextFillColor": "rgb(0, 0, 0)", "whiteSpace": "pre", "letterSpacing": "0px", "lineHeight": "1.2", "tabSize": 4, "fontFamily": "\".SFNSDisplay-Heavy\", \"SFProDisplay-Heavy\", \"SFUIDisplay-Heavy\", \".SFUIDisplay-Heavy\", sans-serif" } }], "text": "Test" }] }, "height": 96, "constraintValues": { "left": null, "height": 96, "centerAnchorX": 0.5013333333333333, "width": 162, "top": null, "centerAnchorY": 0.50074962518740629 }, "blending": "normal", "autoSize": true, "y": 286 })
 			text.fontFamily.should.equal "-apple-system"

 		it "should infer letterSpacing from design", ->
-			text = new TextLayer({ "name": "text", "backgroundColor": null, "width": 162, "x": 107, "styledText": { "blocks": [{ "inlineStyles": [{ "startIndex": 0, "endIndex": 4, "css": { "fontSize": "80px", "WebkitTextFillColor": "rgb(0, 0, 0)", "whiteSpace": "pre", "letterSpacing": "0px", "lineHeight": "1.2", "tabSize": 4, "fontFamily": "\".SFNSDisplay-Heavy\", \"SFProDisplay-Heavy\", \"SFUIDisplay-Heavy\", \".SFUIDisplay-Heavy\", sans-serif" } }], "text": "Test" }] }, "height": 96, "constraintValues": { "left": null, "height": 96, "centerAnchorX": 0.5013333333333333, "width": 162, "top": null, "centerAnchorY": 0.50074962518740629 }, "blending": "normal", "autoSize": true, "y": 286 });
+			text = new TextLayer({ "name": "text", "backgroundColor": null, "width": 162, "x": 107, "styledText": { "blocks": [{ "inlineStyles": [{ "startIndex": 0, "endIndex": 4, "css": { "fontSize": "80px", "WebkitTextFillColor": "rgb(0, 0, 0)", "whiteSpace": "pre", "letterSpacing": "0px", "lineHeight": "1.2", "tabSize": 4, "fontFamily": "\".SFNSDisplay-Heavy\", \"SFProDisplay-Heavy\", \"SFUIDisplay-Heavy\", \".SFUIDisplay-Heavy\", sans-serif" } }], "text": "Test" }] }, "height": 96, "constraintValues": { "left": null, "height": 96, "centerAnchorX": 0.5013333333333333, "width": 162, "top": null, "centerAnchorY": 0.50074962518740629 }, "blending": "normal", "autoSize": true, "y": 286 })
 			text.letterSpacing.should.equal 0

 		it "should infer textAlign from design", ->
-			text = new TextLayer({ "name": "text", "backgroundColor": null, "width": 162, "x": 107, "styledText": { "blocks": [{ "inlineStyles": [{ "startIndex": 0, "endIndex": 4, "css": { "fontSize": "80px", "WebkitTextFillColor": "rgb(0, 0, 0)", "whiteSpace": "pre", "letterSpacing": "0px", "lineHeight": "1.2", "tabSize": 4, "fontFamily": "\".SFNSDisplay-Heavy\", \"SFProDisplay-Heavy\", \"SFUIDisplay-Heavy\", \".SFUIDisplay-Heavy\", sans-serif" } }], "text": "Test" }] }, "height": 96, "constraintValues": { "left": null, "height": 96, "centerAnchorX": 0.5013333333333333, "width": 162, "top": null, "centerAnchorY": 0.50074962518740629 }, "blending": "normal", "autoSize": true, "y": 286 });
+			text = new TextLayer({ "name": "text", "backgroundColor": null, "width": 162, "x": 107, "styledText": { "blocks": [{ "inlineStyles": [{ "startIndex": 0, "endIndex": 4, "css": { "fontSize": "80px", "WebkitTextFillColor": "rgb(0, 0, 0)", "whiteSpace": "pre", "letterSpacing": "0px", "lineHeight": "1.2", "tabSize": 4, "fontFamily": "\".SFNSDisplay-Heavy\", \"SFProDisplay-Heavy\", \"SFUIDisplay-Heavy\", \".SFUIDisplay-Heavy\", sans-serif" } }], "text": "Test" }] }, "height": 96, "constraintValues": { "left": null, "height": 96, "centerAnchorX": 0.5013333333333333, "width": 162, "top": null, "centerAnchorY": 0.50074962518740629 }, "blending": "normal", "autoSize": true, "y": 286 })
 			text.textAlign.should.equal "auto"

 		it "should infer fontWeight from design with custom font", ->
-			text = new TextLayer({"name":"text","backgroundColor":null,"width":70,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":3,"css":{"fontSize":"40px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","fontWeight":400,"letterSpacing":"0px","tabSize":4,"fontFamily":"\"Roboto-Regular\", \"Roboto\", sans-serif","lineHeight":"1.2"}}],"text":"Ben"}],"alignment":"center"},"height":48,"constraintValues":{"height":48,"width":70},"blending":"normal","autoSize":true});
+			text = new TextLayer({"name":"text","backgroundColor":null,"width":70,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":3,"css":{"fontSize":"40px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","fontWeight":400,"letterSpacing":"0px","tabSize":4,"fontFamily":"\"Roboto-Regular\", \"Roboto\", sans-serif","lineHeight":"1.2"}}],"text":"Ben"}],"alignment":"center"},"height":48,"constraintValues":{"height":48,"width":70},"blending":"normal","autoSize":true})
 			text.fontWeight.should.equal 400

 		it "should infer fontFamily from design with custom font", ->
-			text = new TextLayer({"name":"text","backgroundColor":null,"width":70,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":3,"css":{"fontSize":"40px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","fontWeight":400,"letterSpacing":"0px","tabSize":4,"fontFamily":"\"Roboto-Regular\", \"Roboto\", sans-serif","lineHeight":"1.2"}}],"text":"Ben"}],"alignment":"center"},"height":48,"constraintValues":{"height":48,"width":70},"blending":"normal","autoSize":true});
+			text = new TextLayer({"name":"text","backgroundColor":null,"width":70,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":3,"css":{"fontSize":"40px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","fontWeight":400,"letterSpacing":"0px","tabSize":4,"fontFamily":"\"Roboto-Regular\", \"Roboto\", sans-serif","lineHeight":"1.2"}}],"text":"Ben"}],"alignment":"center"},"height":48,"constraintValues":{"height":48,"width":70},"blending":"normal","autoSize":true})
 			text.fontFamily.should.equal "Roboto"

 		it "should infer letterSpacing from design with custom font", ->
-			text = new TextLayer({"name":"text","backgroundColor":null,"width":70,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":3,"css":{"fontSize":"40px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","fontWeight":400,"letterSpacing":"0px","tabSize":4,"fontFamily":"\"Roboto-Regular\", \"Roboto\", sans-serif","lineHeight":"1.2"}}],"text":"Ben"}],"alignment":"center"},"height":48,"constraintValues":{"height":48,"width":70},"blending":"normal","autoSize":true});
+			text = new TextLayer({"name":"text","backgroundColor":null,"width":70,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":3,"css":{"fontSize":"40px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","fontWeight":400,"letterSpacing":"0px","tabSize":4,"fontFamily":"\"Roboto-Regular\", \"Roboto\", sans-serif","lineHeight":"1.2"}}],"text":"Ben"}],"alignment":"center"},"height":48,"constraintValues":{"height":48,"width":70},"blending":"normal","autoSize":true})
 			text.letterSpacing.should.equal 0

 		it "should infer textAlign from design with custom font", ->
-			text = new TextLayer({"name":"text","backgroundColor":null,"width":70,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":3,"css":{"fontSize":"40px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","fontWeight":400,"letterSpacing":"0px","tabSize":4,"fontFamily":"\"Roboto-Regular\", \"Roboto\", sans-serif","lineHeight":"1.2"}}],"text":"Ben"}],"alignment":"center"},"height":48,"constraintValues":{"height":48,"width":70},"blending":"normal","autoSize":true});
+			text = new TextLayer({"name":"text","backgroundColor":null,"width":70,"styledText":{"blocks":[{"inlineStyles":[{"startIndex":0,"endIndex":3,"css":{"fontSize":"40px","WebkitTextFillColor":"rgb(0, 0, 0)","whiteSpace":"pre","fontWeight":400,"letterSpacing":"0px","tabSize":4,"fontFamily":"\"Roboto-Regular\", \"Roboto\", sans-serif","lineHeight":"1.2"}}],"text":"Ben"}],"alignment":"center"},"height":48,"constraintValues":{"height":48,"width":70},"blending":"normal","autoSize":true})
 			text.textAlign.should.equal "center"

 		it "sets the weight if the font property is set", ->


change the intialization

change the intialization

--- atmospheric/002-accumulated-heat/accumulator.coffee
+++ atmospheric/002-accumulated-heat/accumulator.coffee
@@ -29,7 +29,9 @@
     totalB = 0
     data = []
     for i in [0..256]
-        arr = (0 for j in [0..256])
+        arr = []
+        for j in [0..256]
+            arr.push 0
         data.push arr

     input = (lng, lat, time, light1, light2) ->


Removing {@prop: value} from the grammar.

--- grammar.coffee
+++ grammar.coffee
@@ -140,7 +140,6 @@
   AssignObj: [
     o "Identifier ASSIGN Expression",           -> new AssignNode new ValueNode($1), $3, 'object'
     o "AlphaNumeric ASSIGN Expression",         -> new AssignNode new ValueNode($1), $3, 'object'
-    o "ThisProperty ASSIGN Expression",         -> new AssignNode new ValueNode($1), $3, 'this'
     o "Comment"
   ]

@@ -246,16 +245,7 @@
     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 SimpleAssignable",                            -> new ClassNode $2
-    o "CLASS SimpleAssignable EXTENDS Value",              -> new ClassNode $2, $4
-    o "CLASS SimpleAssignable IndentedAssignList",         -> new ClassNode $2, null, $3
-    o "CLASS SimpleAssignable 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: [
@@ -270,6 +260,28 @@
   IndentedAssignList: [
     o "INDENT AssignList OUTDENT",              -> $2
     o "INDENT AssignList , OUTDENT",            -> $2
+  ]
+
+  # Class definitions have optional bodies of prototype property assignments,
+  # and optional references to the superclass.
+  Class: [
+    o "CLASS SimpleAssignable",                            -> new ClassNode $2
+    o "CLASS SimpleAssignable EXTENDS Value",              -> new ClassNode $2, $4
+    o "CLASS SimpleAssignable INDENT ClassBody OUTDENT",   -> new ClassNode $2, null, $4
+    o "CLASS SimpleAssignable EXTENDS Value INDENT ClassBody OUTDENT", -> new ClassNode $2, $4, $6
+  ]
+
+  # Assignments that can happen directly inside a class declaration.
+  ClassAssign: [
+    o "AssignObj",                              -> $1
+    o "ThisProperty ASSIGN Expression",         -> new AssignNode new ValueNode($1), $3, 'this'
+  ]
+
+  # A list of assignments to a class.
+  ClassBody: [
+    o "",                                       -> []
+    o "ClassAssign",                            -> [$1]
+    o "ClassBody TERMINATOR ClassAssign", -> $1.concat $3
   ]

   # The three flavors of function call: normal, object instantiation with `new`,


Fix: unable to parse end of the document marker (...)

In Regexp, '^' and '$' by default match the beginning and end of the
whole string rather than a single line. In Parser.parse(), each line is
a separate string, so this is fine. But in Parser.cleanup(), the whole
document is a single string. To allow '^' and '$' matching the beginning
and end of line in this string, we need modifier 'm' to make RegExp work
in multiline mode.

--- src/Parser.coffee
+++ src/Parser.coffee
@@ -19,10 +19,10 @@
     PATTERN_DECIMAL:                        new Pattern '\\d+'
     PATTERN_INDENT_SPACES:                  new Pattern '^ +'
     PATTERN_TRAILING_LINES:                 new Pattern '(\n*)$'
-    PATTERN_YAML_HEADER:                    new Pattern '^\\%YAML[: ][\\d\\.]+.*\n'
-    PATTERN_LEADING_COMMENTS:               new Pattern '^(\\#.*?\n)+'
-    PATTERN_DOCUMENT_MARKER_START:          new Pattern '^\\-\\-\\-.*?\n'
-    PATTERN_DOCUMENT_MARKER_END:            new Pattern '^\\.\\.\\.\\s*$'
+    PATTERN_YAML_HEADER:                    new Pattern '^\\%YAML[: ][\\d\\.]+.*\n', 'm'
+    PATTERN_LEADING_COMMENTS:               new Pattern '^(\\#.*?\n)+', 'm'
+    PATTERN_DOCUMENT_MARKER_START:          new Pattern '^\\-\\-\\-.*?\n', 'm'
+    PATTERN_DOCUMENT_MARKER_END:            new Pattern '^\\.\\.\\.\\s*$', 'm'
     PATTERN_FOLDED_SCALAR_BY_INDENTATION:   {}

     # Context types


Troubleshoot: tourbleshoot.coffee file is included

--- client/Main/includes.coffee
+++ client/Main/includes.coffee
@@ -197,6 +197,9 @@
   # global notifications
   "globalnotification.coffee",

+  # trouble shooter
+  "troubleshoot.coffee",
+
   # avatararea
   "avatararea/avatararea.coffee",
   "avatararea/avatarareapopup.coffee",


Modified to return the clone of properties

--- src/Sprite.coffee
+++ src/Sprite.coffee
@@ -28,7 +28,7 @@
   size: (w, h) ->
     switch arguments.length
       when 0
-        return @_size
+        return {w: @_size.w, h: @_size.h}

       when 1
         size = w
@@ -41,13 +41,14 @@

     @style.width = "#{@_size.w}px"
     @style.height = "#{@_size.h}px"
+
     @imageClip @_imageClip
     return @

   position: (x, y, z) ->
     switch arguments.length
       when 0
-        return @_pos
+        return {x: @_pos.x, y: @_pos.y, z: @_pos.z}

       when 1
         pos = x
@@ -67,7 +68,7 @@
   rotation: (x, y, z) ->
     switch arguments.length
       when 0
-        return @_rot
+        return {x: @_rot.x, y: @_rot.y, z: @_rot.z}

       when 1
         rot = x
@@ -87,7 +88,7 @@
   scale: (x, y, z) ->
     switch arguments.length
       when 0
-        return @_scl
+        return {x: @_scl.x, y: @_scl.y, z: @_scl.z}

       when 1
         scl = x
@@ -104,71 +105,8 @@
     @style[DivSugar._transform] = @_ps + @_rs + @_ss
     return @

-  visible: (visible) ->
-    if arguments.length == 0
-      return @_visible
-    else
-      @_visible = visible
-      @style.visibility = if visible then "visible" else "hidden"
-      return @
-
-  clip: (clip) ->
-    if arguments.length == 0
-      return @_clip
-    else
-      @_clip = clip
-      @style.overflow = if clip then "hidden" else "visible"
-      return @
-
-  opacity: (opacity) ->
-    if arguments.length == 0
-      return @_opacity
-    else
-      @_opacity = @style.opacity = opacity
-      return @
-
-  image: (imageUrlOrColor) ->
-    if arguments.length == 0
-      return @_image
-    else
-      @_image = imageUrlOrColor
-
-      if not imageUrlOrColor?
-        @style.backgroundColor = null
-        @style.backgroundImage = null
-      else if imageUrlOrColor.charAt(0) == '#'
-        @style.backgroundColor = imageUrlOrColor
-        @style.backgroundImage = null
-      else
-        @style.backgroundColor = null
-        @style.backgroundImage = "url(#{imageUrlOrColor})"
-
-      return @
-
-  imageClip: (u1, v1, u2, v2) ->
-    switch arguments.length
-      when 0
-        return @_imageClip
-
-      when 1
-        imageClip = u1
-        @_imageClip.u1 = imageClip.u1
-        @_imageClip.v1 = imageClip.v1
-        @_imageClip.u2 = imageClip.u2
-        @_imageClip.v2 = imageClip.v2
-
-      else
-        @_imageClip.u1 = u1
-        @_imageClip.v1 = v1
-        @_imageClip.u2 = u2
-        @_imageClip.v2 = v2
-
-    w = @_size.w / (@_imageClip.u2 - @_imageClip.u1)
-    h = @_size.h / (@_imageClip.v2 - @_imageClip.v1)
-    x = -@_imageClip.u1 * w
-    y = -@_imageClip.v1 * h
-
-    @style.backgroundPosition = "#{x}px #{y}px"
-    @style.backgroundSize = "#{w}px #{h}px"
-
-    return @
+  visible: DivSugar._Scene.visible
+  clip: DivSugar._Scene.clip
+  opacity: DivSugar._Scene.opacity
+  image: DivSugar._Scene.image
+  imageClip: DivSugar._Scene.imageClip


IDE: use new ResourceStateModal

IDE: use new ResourceStateModal

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -751,13 +751,7 @@
     container   ?= @getView()
     modalOptions = { state, container, initial }

-    if checkFlag 'new-resource-state-modal'
-      @machineStateModal = new ResourceStateModal modalOptions, machineItem
-    else
-      if isTeamReactSide() and state is Stopping
-        modalOptions.cssClass = 'env-machine-state team full'
-      @machineStateModal = new EnvironmentsMachineStateModal modalOptions, machineItem
-
+    @machineStateModal = new ResourceStateModal modalOptions, machineItem
     @machineStateModal.once 'KDObjectWillBeDestroyed', => @machineStateModal = null
     @machineStateModal.once 'IDEBecameReady', @bound 'handleIDEBecameReady'


FinderPane: Add missing filetree snyc event handler.

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -153,6 +153,8 @@

     {@finderPane, @settingsPane} = @workspace.panel.getPaneByName 'filesPane'

+    @finderPane.on 'ChangeHappened', @bound 'syncChange'
+
     @bindRouteHandler()
     @initiateAutoSave()
     @emit 'ready'


Remove old commented-out code

Remove old commented-out code

--- js/inner.coffee
+++ js/inner.coffee
@@ -298,43 +298,4 @@

 $(document).ready () ->
   SammyApp.run window.location.pathname.replace(/(.+)\/$/, "$1")
-  _kmq.push(['identify', VM.current_user().login])
-
-
-
-
-# # Events
-#   events:
-#     "click #reset": "reset_specs"
-#     "click #trigger": "trigger_build"
-#     "click #trigger_inferred": "trigger_inferred_build"
-
-#   save: (event, btn, redirect, keys) ->
-#     event.preventDefault()
-#     btn.button 'loading'
-
-#     m.save {},
-#       success: ->
-#         btn.button 'reset'
-#         window.location = redirect
-#       error: ->
-#         btn.button 'reset'
-#         alert "Error in saving project. Please try again. If it persists, please contact Circle."
-
-#   reset_specs: (e) ->
-#     @model.set
-#       "setup": ""
-#       "compile": ""
-#       "test": ""
-#       "extra": ""
-#       "dependencies": ""
-
-#   trigger_build: (e, payload = {}) ->
-#     e.preventDefault()
-#     btn = $(e.currentTarget)
-#     btn.button 'loading'
-#     $.post @model.build_url(), payload, () ->
-#       btn.button 'reset'
-
-#   trigger_inferred_build: (e) ->
-#     @trigger_build e, {inferred: true}
+  _kmq.push(['identify', VM.current_user().login])


add request object to authorizer params

add request object to authorizer params

--- src/action.coffee
+++ src/action.coffee
@@ -52,7 +52,7 @@
       schemes = [schemes]

     if schemes? && @client.context.authorizer?
-      result = @client.context.authorizer(schemes, resource, @name)
+      result = @client.context.authorizer(schemes, resource, @name, request)
       if result?
         {scheme, credential} = result
         request.headers["Authorization"] = "#{scheme} #{credential}"


fan speed control

fan speed control

--- grow-systems.coffee
+++ grow-systems.coffee
@@ -69,7 +69,7 @@
 			@state.power = fan.state
 			@state.speed = .3 #TODO remove

-			@power 1 #run fan
+			@power = 1 #run fan

 			@fan = fan  if debug.mode
 			debug.log "Init Air. Fan is #{ debug.stateTxt[@state.power] }"


Snap drag while number scrubbing by holding command key

--- src/View/ExpressionCode.coffee
+++ src/View/ExpressionCode.coffee
@@ -2,6 +2,7 @@
 require "codemirror/mode/javascript/javascript"
 CodeMirror = require "codemirror"
 _ = require "underscore"
+key = require "keymaster"
 R = require "./R"
 Model = require "../Model/Model"
 Util = require "../Util/Util"
@@ -369,8 +370,8 @@
         dx = dx / 3
         delta = dx * Math.pow(10, -precision)
         newValue = originalValue + delta
-        # if key.command
-        #   newValue = Util.roundToPrecision(newValue, precision - 1)
+        if key.command
+          newValue = Util.roundToPrecision(newValue, precision - 1)
         newValue = Util.toPrecision(newValue, precision)
         @mirror.replaceSelection(""+newValue, "around")


Add invoice link to transaction list.

Add invoice link to transaction list.

--- node_modules_koding/koding-payment/lib/main.coffee
+++ node_modules_koding/koding-payment/lib/main.coffee
@@ -461,9 +461,11 @@
               datetime  : t.created_at[0]['_']
               refundable: t.refundable[0]['_']
               source    : t.source[0]
+            if t.invoice
+              trans.invoice = t.invoice[0]['$']['href']
             if trans.status in ['success', 'void']
-              trans.owner  = "#{unescape billing.first_name[0]} #{unescape billing.last_name[0]}"
-              trans.card   = "#{billing.card_type[0]} - #{billing.first_six.toString().substring(0,4)}-...-#{billing.last_four}"
+              trans.owner   = "#{unescape billing.first_name[0]} #{unescape billing.last_name[0]}"
+              trans.card    = "#{billing.card_type[0]} - #{billing.first_six.toString().substring(0,4)}-...-#{billing.last_four}"
             transactions.push trans
       callback no, transactions


Pretty tracebacks for CoffeeScript

Pretty tracebacks for CoffeeScript

--- src/bundle.coffee
+++ src/bundle.coffee
@@ -144,7 +144,25 @@
               try
                 body = compilers[file.ext](body, filename)
               catch err
-                return cb new Error "Error: Failed to compile #{filename}"
+                if file.ext == 'coffee'
+                  lineno = /Parse error on line (\d+)/.exec(err.message)[1]
+                  cb err if not lineno
+
+                  n = parseInt lineno, 10
+
+                  lines = body.split '\n'
+                  extra = []
+                  for i in [n-4..n+3]
+                    continue if i < 0
+
+                    if lines[i]
+                      if i+1 == n
+                        extra.push " > #{i+1}. #{lines[i]}"
+                      else
+                        extra.push "   #{i+1}. #{lines[i]}"
+
+                  err.stack = "\n#{extra.join('\n')}\n\n#{err.stack}"
+                  return cb err

               # Find all dependencies that are required
               file.ast = parse body


revokeInvite and getInviteByToken functions.

--- services/web/app/coffee/Features/Collaborators/CollaboratorsInviteHandler.coffee
+++ services/web/app/coffee/Features/Collaborators/CollaboratorsInviteHandler.coffee
@@ -35,7 +35,23 @@
 				callback(null, invite)

 	revokeInvite: (projectId, inviteId, callback=(err)->) ->
+		logger.log {projectId, inviteId}, "removing invite"
+		ProjectInvite.remove {projectId: projectId, _id: inviteId}, (err) ->
+			if err?
+				logger.err {err, projectId, inviteId}, "error removing invite"
+				return callback(err)
+			callback(null)

 	getInviteByToken: (projectId, tokenString, callback=(err,invite)->) ->
+		logger.log {projectId, tokenString}, "fetching invite by token"
+		ProjectInvite.findOne {projectId: projectId, token: tokenString}, (err, invite) ->
+			if err?
+				logger.err {err, projectId, inviteId}, "error fetching invite"
+				return callback(err)
+			now = new Date()
+			if invite.expiresAt < now
+				logger.log {projectId, inviteId, expiresAt: invite.expiresAt}, "invite expired"
+				return callback(null, null)
+			callback(null, invite)

 	acceptInvite: (projectId, inviteId, callback=(err)->) ->


Only raise a worker error event if someone is listening.

--- src/client.coffee
+++ src/client.coffee
@@ -64,9 +64,7 @@
     if handle.callback?
       handle.callback data, handle
       handle.callback = undefined
-      handle.emit "error", data unless _(handle.listeners("error")).isEmpty()
-    else
-      handle.emit "error", data
+    handle.emit "error", data unless _(handle.listeners("error")).isEmpty()
     @_removeHandle handle

   _addHandle: (handle) ->


Emit profilesLoaded

Emit profilesLoaded

--- src/client.coffee
+++ src/client.coffee
@@ -67,6 +67,7 @@
         if data
             @users = data
             @logger.debug 'Found '+Object.keys(@users).length+' profiles.'
+            @emit 'profilesLoaded', { profiles: @users }
         else
             @logger.error 'Failed to load profiles from server.'
             @emit 'error', { msg: 'failed to load profiles'}


add new datapipeline resources

add new datapipeline resources

--- src/coffin.coffee
+++ src/coffin.coffee
@@ -37,6 +37,8 @@
         Application: null
         DeploymentConfig: null
         DeploymentGroup: null
+      DataPipeline:
+        Pipeline: null
       DynamoDB:
         Table: null
       EC2:


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color2.coffee
+++ src/color2.coffee
@@ -43,14 +43,14 @@
     return undefined unless channels = hslParser.exec(colorString)

     parsedColor = (parseFloat channel for channel in channels[1..3])
-    parsedColor[0] = parsedColor[0].floor()
+    parsedColor[0] = parsedColor[0].round()
     parsedColor[3] ||= 1.0

     return hslToRgb(parsedColor)

   hslToRgb = (hsl) ->
     [h, s, l, a] = (parseFloat(channel) for channel in hsl)
-    h = h.floor()
+    h = h.round()
     h /= 360.0
     a ||= 1.0


Remove the deep clone in component preprocessor. For #13

--- src/common.coffee
+++ src/common.coffee
@@ -121,7 +121,6 @@
   ACTION_TYPES: ACTION_TYPES

   preprocess: (q) ->
-    q = _.cloneDeep q
     query = canonicalizeQuery q
     options = canonicalizeOpts q
     q.query = query


Prepare for log rotation.

Prepare for log rotation.

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -24,6 +24,9 @@
     { level: argv.logLevel, path: "#{argv.logDir}/sphere-price-sync_#{argv.projectKey}.log" }
   ]

+process.on 'SIGUSR2', ->
+  logger.reopenFileStreams()
+
 options =
   baseConfig:
     timeout: argv.timeout


panic mode

panic mode

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -14,7 +14,7 @@

 Rx = require 'rx'
 Q = require 'q'
-{_} = require('underscore')
+{_} = require 'underscore'
 express = require 'express'

 messageProcessors = [((m)-> Q(m)), ((m)-> Q(m)), ((m)-> Q(m))]
@@ -46,7 +46,8 @@
     @locallyLocked = 0
     @lockedMessages = 0
     @newMessages = 0
-    @lockedFailedMessages = 0
+    @lockFailedMessages = 0
+    @panicMode = false

   get: ->
     started: @started
@@ -55,11 +56,12 @@
     locallyLocked: @locallyLocked
     lockedMessages: @lockedMessages
     newMessages: @newMessages
-    lockedFailedMessages: @lockedFailedMessages
+    lockFailedMessages: @lockFailedMessages
+    panicMode: @panicMode

   applyBackpressureAtTick: (tick) ->
     @lastTick = tick
-    @messagesInProgress() is 0
+    @panicMode or @messagesInProgress() is not 0

   messagesInProgress: () ->
     @messagesIn - @messagesOut
@@ -74,7 +76,6 @@
   lockedMessage: (msg) ->
     @lockedMessages = @lockedMessages + 1

-
   unlockedMessage: (msg) ->
     @lockedMessages = @lockedMessages + 1

@@ -82,7 +83,7 @@
     @messagesOut = @messagesOut + 1

   failedLock: (msg) ->
-    @lockedFailedMessages = @lockedFailedMessages + 1
+    @lockFailedMessages = @lockFailedMessages + 1

 class BatchMessageService
   constructor: ->
@@ -149,7 +150,7 @@
 allMessages = Rx.Observable
 .interval(500)
 .filter (tick) ->
-  stats.applyBackpressureAtTick(tick)
+  not stats.applyBackpressureAtTick(tick)
 .flatMap ->
   messageService.getMessages()
 .map (msg) ->
@@ -217,11 +218,21 @@
   persistenceService.reportMessageProcessingFailure m, m.processingResults
 .subscribe recycleBin

+initiateSelfDestructionSequence = ->
+  Rx.Observable.interval(500).subscribe ->
+    if stats.messagesInProgress() is 0
+      console.info "Graceful exit", stats.get()
+      process.exit 0

 statsApp = express()

 statsApp.get '/', (req, res) ->
   res.json stats.get()
+
+statsApp.get '/stop', (req, res) ->
+  res.send 'Ok'
+  stats.panicMode = true
+  initiateSelfDestructionSequence()

 statsApp.listen 7777, ->
   console.log "Statistics is on port 7777"
@@ -229,6 +240,4 @@
 Rx.Observable.interval(3000).subscribe ->
   console.info "+-------------------------------"
   console.info stats.get()
-  console.info "+-------------------------------"
-
-
+  console.info "+-------------------------------"


pause mode

pause mode

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -38,6 +38,7 @@
     @units = options.units or [{name: "Second", rateUnit: 1000}, {name: "Minute", rateUnit: 60 * 1000}]
     @started = new Date()
     @panicMode = false
+    @paused = false
     @locallyLocked = 0
     @lastTick = -1

@@ -61,10 +62,11 @@
     lockFailedMessages: @lockFailedMessages.toJSON()
     processingErrors: @processingErrors.toJSON()
     panicMode: @panicMode
+    paused: @paused

   applyBackpressureAtTick: (tick) ->
     @lastTick = tick
-    @panicMode or @messagesInProgress() is not 0
+    @paused or @panicMode or @messagesInProgress() is not 0

   messagesInProgress: () ->
     @messagesIn.count() - @messagesOut.count()
@@ -104,9 +106,29 @@
       res.json @toJSON()

     statsApp.get '/stop', (req, res) =>
-      res.send 'Ok'
+      res.json
+        message: 'Self destruction sequence initiated!'
+
       @panicMode = true
       @_initiateSelfDestructionSequence()
+
+    statsApp.get '/pause', (req, res) =>
+      if @paused
+        res.json
+          message: "Already paused."
+      else
+        @paused = true
+        res.json
+          message: "Done."
+
+    statsApp.get '/resume', (req, res) =>
+      if not @paused
+        res.json
+          message: "Already running."
+      else
+        @paused = false
+        res.json
+          message: "Done."

     statsApp.listen port, ->
       console.log "Statistics is on port 7777"


Use debug log level

Use debug log level

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -360,7 +360,7 @@
       .then (sftp) ->
         sourceFolder = config.sftp_directories.import[code].source
         fileRegex = config.sftp_directories.import[code].fileRegex
-        logger.info "Check for new '#{code}' in: '#{sourceFolder}'"
+        logger.debug "Check for new '#{code}' in: '#{sourceFolder}'"
         sftpClient.downloadAllFiles(sftp, tmpPath, sourceFolder, fileRegex)
         .then ->
           sftpClient.close(sftp)


Get rid of getLength in Collection for better performance

There is no need to loop among all items for updating the length.

--- src/collection.coffee
+++ src/collection.coffee
@@ -1,28 +1,23 @@
 {Events} = require './events'
 {indexOf, extend, serializeObject, get} = require './helpers'

-isArrayIndex = (index) -> index.match(/^\d+$/)
-
-getLength = (arr) ->
-  indices = (parseInt(index, 10) for index, val of arr when isArrayIndex(index))
-  if indices.length then Math.max(indices...) + 1 else 0
+isArrayIndex = (index) -> "#{index}".match(/^\d+$/)

 class exports.Collection
   extend(@prototype, Events)
   constructor: (list) ->
     @[index] = val for val, index in list
-    @length = getLength(@)
+    @length = list?.length or 0
   get: (index) -> @[index]
   set: (index, value) ->
     @[index] = value
-    @length = getLength(@)
+    @length = Math.max(@length, index + 1) if isArrayIndex(index)
     @trigger("change:#{index}", value)
     @trigger("set", index, value)
     @trigger("change", @)
     value
   push: (element) ->
-    @[@length] = element
-    @length = getLength(@)
+    @[@length++] = element
     @trigger("add", element)
     @trigger("change", @)
     element
@@ -33,7 +28,7 @@
     old = @clone()
     delete @[index] for index, _ of @ when isArrayIndex(index)
     @[index] = val for val, index in list
-    @length = getLength(@)
+    @length = list?.length or 0
     @trigger("update", old, @)
     @trigger("change", @)
     list


Using our writing style

Using our writing style

--- src/collection.coffee
+++ src/collection.coffee
@@ -46,7 +46,7 @@
 			element['$updated'] = date
 			@items.push element
 		@save()
-		@items
+		return @items

 	# Retrieving data functions
 	get: (cid) ->  _.findWhere(@items, {'cid': cid})


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/collidable.coffee
+++ src/collidable.coffee
@@ -15,6 +15,7 @@

     self.attrAccessor(
       "immovable"
+      "velocity"
     )

     solid: (newSolid) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/controllable.coffee
+++ src/controllable.coffee
@@ -18,7 +18,7 @@

   # the player is moved left according to his speed
   player.I.x
-  # => 2.5 # half the player's width
+  # => 13

   player.I.y
   # => 311.5 # The default App.height (320) - half the player's height


GitLab: OAuth: provide more information about the oauth process on error

--- servers/lib/server/gitlab_callback.coffee
+++ servers/lib/server/gitlab_callback.coffee
@@ -17,6 +17,7 @@
 fetchUserInfo = (req, res, access_token) -> (error, response, body) ->

   if error or not id = body.id
+    console.error '[GITLAB] Failed fetch user info:', error
     return fail req, res

   { username, id, email, name } = body
@@ -46,6 +47,7 @@
 authorizeUser = (req, res) -> (error, response, body) ->

   if error or not access_token = body.access_token
+    console.error '[GITLAB] Failed to get access_token:', error
     return fail req, res

   options   =
@@ -59,7 +61,9 @@

 module.exports = (req, res) ->

-  return fail req, res  unless code = req.query.code
+  unless code = req.query.code
+    console.error '[GITLAB] Failed to get code from query:', req.query
+    return fail req, res

   options           =
     url             : getUrlFor '/oauth/token'


remove debug print statment

remove debug print statment

--- csi.coffee
+++ csi.coffee
@@ -364,7 +364,6 @@
             if a.order < b.order
               return -1
             return 0
-          (console.log css.name for css in ordered)
           (css.contents for css in ordered).join("\n")

         # return the contents of `filename` w/ the css url(...) paths


Make # optional in clone command

Make # optional in clone command


More work on statements

More work on statements

--- grammars/d.cson
+++ grammars/d.cson
@@ -998,52 +998,106 @@
     },
     'for-statement': {
       'patterns': [
-
+        {
+          'match': 'for',
+          'name': 'keyword.control.for.d'
+        },
+        {
+          'begin': '\\(',
+          'beginCaptures': { '0': { 'name': 'support.type.parens-expression.begin.d' } },
+          'end': '\\)',
+          'encCaptures': { '0': { 'name': 'support.type.parens-expression.end.d' } },
+          'patterns': [
+            { 'include': '#initialize' },
+            { 'include': '#test' },
+            { 'include': '#semi-colon' },
+            { 'include': '#increment' }
+        },
+        { 'include': '#scope-statement' }
       ]
     },
     'initialize': {
       'patterns': [
-
+        { 'include': '#semi-colon' },
+        { 'include': '#no-scope-non-empty-statement' }
       ]
     },
     'test': {
       'patterns': [
-
+        { 'include': '#expression' }
       ]
     },
     'increment': {
       'patterns': [
-
+        { 'include': '#expression' }
       ]
     },
     'foreach-statement': {
       'patterns': [
-
+        { 'include': '#foreach' },
+        {
+          'begin': '\\(',
+          'beginCaptures': { '0': { 'name': 'support.type.parens-expression.begin.d' } },
+          'end': '\\)',
+          'encCaptures': { '0': { 'name': 'support.type.parens-expression.end.d' } },
+          'patterns': [
+            { 'include': '#foreach-type-list' },
+            { 'include': '#semi-colon' },
+            { 'include': '#foreach-aggregate' },
+          ]
+        },
+        { 'include': '#no-scope-non-empty-statement' }
       ]
     },
     'foreach': {
       'patterns': [
-
+        'match': 'foreach|foreach_reverse',
+        'name': 'keyword.control.foreach.d'
       ]
     },
     'foreach-type-list': {
       'patterns': [
-
+        { 'include': '#foreach-type' },
+        { 'include': '#comma' }
       ]
     },
     'for-each-type': {
       'patterns': [
-
+        {
+          'match': 'ref\\s+',
+          'name': 'storage.modifier.ref.d'
+        },
+        { 'include': '#type-ctors' },
+        { 'include': '#basic-type' },
+        { 'include': '#declarator' },
+        { 'include': '#identifier' }
       ]
     },
     'foreach-aggregate': {
       'patterns': [
-
+        { 'include': '#expression' }
       ]
     },
     'foreach-range-statement': {
       'patterns': [
-
+        { 'include': '#foreach' },
+        {
+          'begin': '\\(',
+          'beginCaptures': { '0': { 'name': 'support.type.parens-expression.begin.d' } },
+          'end': '\\)',
+          'encCaptures': { '0': { 'name': 'support.type.parens-expression.end.d' } },
+          'patterns': [
+            { 'include': '#foreach-type' },
+            { 'include': '#semi-colon' },
+            { 'include': '#lwr-expression' },
+            {
+              'match': '\\.\\.',
+              'name': 'keyword.operator.range.d'
+            },
+            { 'include': '#upr-expression' },
+          ]
+        },
+        { 'include': '#scope-statement' }
       ]
     },
     'lwr-expression': {


auto pin mode

auto pin mode

--- grovepi.coffee
+++ grovepi.coffee
@@ -55,10 +55,12 @@
 			callback = args[0]
 			writeCmd = 'writeByte'

-		cmdAndData = [ (getCmd cmd) + "[#{cmd}]" ]
-		cmdAndData.push data  if data
+		namedCmd = (getCmd cmd) + "[#{cmd}]"

-		debug.log 'Send', cmdAndData..., 'to port', port
+		portAndData = [ 'to port', port ]
+		portAndData.push 'with data', data  if data
+
+		debug.log 'Send', namedCmd, portAndData

 		writeArgs.push (error) ->
 			callback()


added handler for orderly shutdown, fixture: handle rejections from RED.start to avoid pimatic bailing out with an unhandled exception

--- node-red.coffee
+++ node-red.coffee
@@ -14,20 +14,25 @@
         pimaticFramework:@framework,
         functionGlobalContext: { }
       }
-
+
       appie = express();
       appie.use("/",express.static("public"));
       server = http.createServer(appie);
-
+
       RED.init(server,settings)
       appie.use(settings.httpAdminRoot,RED.httpAdmin)
       appie.use(settings.httpNodeRoot,RED.httpNode)
       server.listen(8000);
-
+
       @framework.on 'server listen', (context)=>
         finished = true
-        RED.start()
+        RED.start().catch (error) =>
+          env.logger.error "Startup failed: ", error
         return
+
+      @framework.once 'destroy', (context) =>
+        context.waitForIt RED.stop()
+
   return new NodeRed


IE8 tutorial fix

IE8 tutorial fix

--- scripts/controllers/Tutorial.coffee
+++ scripts/controllers/Tutorial.coffee
@@ -60,7 +60,7 @@
 		tutorial.message.html @content

 		if @nextOn
-			$(window).on event, selector, tutorial.next for event, selector of @nextOn
+			$(document).on event, selector, tutorial.next for event, selector of @nextOn
 		else
 			buttonsHolder = $('

')
 			continueButtons = translate 'tutorialContinue', 'button'
@@ -78,7 +78,7 @@
 		tutorial.message.html ''

 		if @nextOn
-			$(window).off event, selector, tutorial.next for event, selector of @nextOn
+			$(document).off event, selector, tutorial.next for event, selector of @nextOn
 		else
 			tutorial.message.off 'click', '.continue button', tutorial.next


activity: add SET_CHANNEL_UNREAD_COUNT action type

--- client/activity/lib/flux/actions/actiontypes.coffee
+++ client/activity/lib/flux/actions/actiontypes.coffee
@@ -95,6 +95,8 @@
   'DELETE_PRIVATE_CHANNEL_SUCCESS'
   'DELETE_PRIVATE_CHANNEL_FAIL'

+  'SET_CHANNEL_UNREAD_COUNT'
+
   'SET_SUGGESTIONS_QUERY'
   'SET_SUGGESTIONS_VISIBILITY'
   'SET_SUGGESTIONS_ACCESSIBILITY'


Preview: Fix username collision for collaboration.

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -750,8 +750,8 @@
     return unless file

     if FSHelper.isPublicPath file.path
-      # FIXME: Take care of https.
-      prefix      = "[#{@mountedMachineUId}]/home/#{nick()}/Web/"
+      nickname    = @collaborationHost or nick()
+      prefix      = "[#{@mountedMachineUId}]/home/#{nickname}/Web/"
       [temp, src] = file.path.split prefix
       @createNewBrowser "#{@mountedMachine.domain}/#{src}"
     else


Resize all split views when sidebar is collapsed or expanded

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -764,7 +764,8 @@

     @isSidebarCollapsed = yes

-    splitView.emit 'ResizeFirstSplitView'
+    splitView.emit 'ResizeFirstSplitView' # It references to main wrapper split view.
+    @resizeAllSplitViews() # Also resize all split views.

     tabView.on 'PaneDidShow', (pane) ->
       return if pane.options.name is 'Dummy'
@@ -785,6 +786,15 @@
     filesPane.tabView.showPaneByName @activeFilesPaneName

     splitView.emit 'ResizeFirstSplitView'
+    @resizeAllSplitViews()
+
+
+  resizeAllSplitViews: ->
+
+    parents = []
+    @ideViews.forEach (view) -> parents.push view.parent?.parent
+
+    _.uniq(parents, 'id').forEach (p) -> p._windowDidResize()

   toggleSidebar: ->


Update article sorting - sort all queries

--- client/controllers/curatorInbox/curatorInbox.coffee
+++ client/controllers/curatorInbox/curatorInbox.coffee
@@ -43,6 +43,7 @@
   @reviewFilter.set(null)
   @selectedSourceId = new ReactiveVar(null)
   @query = new ReactiveVar(null)
+  @sorting = new ReactiveVar(null)
   @currentPaneInView = new ReactiveVar('')
   @latestSourceDate = new ReactiveVar(null)
   @filtering = new ReactiveVar(false)
@@ -84,13 +85,15 @@
     dateQuery =
       $gte: new Date(startDate)
       $lte: new Date(endDate)
-    sort = sort: publishDate: -1
+    sorting = sort: publishDate: -1
     if query.addedByUserId
-      sort = sort: addedDate: -1
+      sorting = sort: addedDate: -1
       query.addedDate = dateQuery
     else
       query.publishDate = dateQuery

+    @sorting.set(sorting)
+
     @query.set(query)

     Meteor.call 'fetchPromedPosts', 100, range, (err) ->
@@ -101,15 +104,14 @@
     if calendar
       updateCalendarSelection(calendar, range)

-    @subscribe "articles", query, () =>
+    @subscribe "articles", query, =>
       unReviewedQuery = $and: [ {reviewed: false}, query ]
-      firstSource = Articles.findOne(unReviewedQuery, sort)
+      firstSource = Articles.findOne(unReviewedQuery, sorting)
       if firstSource
         @selectedSourceId.set(firstSource._id)
       @filtering.set(false)
       if not @latestSourceDate.get()
-        sort.fields = publishDate: 1
-        @latestSourceDate.set Articles.findOne({}, sort)?.publishDate
+        @latestSourceDate.set Articles.findOne({}, sorting)?.publishDate
       @ready.set(true)

 Template.curatorInbox.onDestroyed ->
@@ -117,7 +119,7 @@

 Template.curatorInbox.helpers
   articles: ->
-    Articles.find()
+    Articles.find({}, Template.instance().sorting.get())

   days: ->
     {startDate, endDate} = Template.instance().dateRange.get()


onboarding: fix for editor settings tab

onboarding: fix for editor settings tab

--- client/ide/lib/views/tabview/idefilestabview.coffee
+++ client/ide/lib/views/tabview/idefilestabview.coffee
@@ -54,9 +54,6 @@

     @tabView.addPane filesPane

-    filesPane.on 'KDTabPaneActive', ->
-      kd.singletons.onboardingController.refreshOnboarding()
-
     @on 'MachineMountRequested', (machineData, rootPath) =>
       @finderPane.emit 'MachineMountRequested', machineData, rootPath

@@ -73,8 +70,11 @@
     settingsPane.addSubView @settingsPane = new IDESettingsPane
     @tabView.addPane settingsPane

+    { onboardingController } = kd.singletons
     settingsPane.on 'KDTabPaneActive', ->
-      kd.singletons.onboardingController.runOnboarding OnboardingEvent.IDESettingsOpened
+      onboardingController.runOnboarding OnboardingEvent.IDESettingsOpened
+    settingsPane.on 'KDTabPaneInactive', ->
+      onboardingController.refreshOnboarding OnboardingEvent.IDESettingsOpened

   # createToggleMenu: ->


Fix brush selection in combination with the d3 zoom behaviour

--- src/d3.timeslider.coffee
+++ src/d3.timeslider.coffee
@@ -51,9 +51,18 @@
         @brush = d3.svg.brush()
             .x(@scales.x)
             .on('brushstart', =>
-                @root.call(@options.zoom.on('zoom', null))
+                @options.lastZoom = {
+                    scale: @options.zoom.scale(),
+                    translate: [
+                        @options.zoom.translate()[0],
+                        @options.zoom.translate()[1],
+                    ]
+                }
+                @options.zoom.on('zoom', null)
             )
             .on('brushend', =>
+                @options.zoom.scale(@options.lastZoom.scale)
+                    .translate(@options.lastZoom.translate).on('zoom', zoom)
                 element.dispatchEvent(
                     new CustomEvent('selectionChanged', {
                         detail: {
@@ -64,10 +73,6 @@
                         cancelable: true
                     })
                 )
-                if @options.lastZoom?
-                    @root.call(@options.zoom.scale(@options.lastZoom.scale()).translate(@options.lastZoom.translate()).on('zoom', zoom))
-                else
-                    @root.call(@options.zoom.on('zoom', zoom))
             )
             .extent([@options.brush.start, @options.brush.end])


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_clear.coffee
+++ src/engine_clear.coffee
@@ -24,7 +24,7 @@
     if I.clear
       I.canvas.clear()
     else if I.background
-
+      I.background.fill()
     else if I.backgroundColor
       I.canvas.fill(I.backgroundColor)


Don’t reopen tags after a fold at a soft line break

--- src/display-layer.coffee
+++ src/display-layer.coffee
@@ -679,14 +679,15 @@
           if spatialDecoration?
             tagsToClose.push(spatialDecoration)

-          if tagsToReopenAfterFold?
-            tagsToOpen.push(tagsToReopenAfterFold...)
-            tagsToReopenAfterFold = null
-
-          if not metadata?.softLineBreak and comparePoints(decorationIterator.getPosition(), bufferStart) is 0
-            tagsToClose.push(decorationIterator.getCloseTags()...)
-            tagsToOpen.push(decorationIterator.getOpenTags()...)
-            decorationIterator.moveToSuccessor()
+          if not metadata?.softLineBreak
+            if tagsToReopenAfterFold?
+              tagsToOpen.push(tagsToReopenAfterFold...)
+              tagsToReopenAfterFold = null
+
+            if comparePoints(decorationIterator.getPosition(), bufferStart) is 0
+              tagsToClose.push(decorationIterator.getCloseTags()...)
+              tagsToOpen.push(decorationIterator.getOpenTags()...)
+              decorationIterator.moveToSuccessor()

         if spatialDecoration = @getSpatialTokenTextDecoration(metadata)
           tagsToOpen.push(spatialDecoration)


Adjust row counter to also work with bigger chunks.

--- src/coffee/csv/importer.coffee
+++ src/coffee/csv/importer.coffee
@@ -38,11 +38,12 @@

       __(input).pipe(parser).pipe(transformer).pipe(
         transform (chunk, cb) =>
+          chunkSize = 1
           console.log "Process row: " + rowCount
           @logger.debug 'chunk: ', chunk, {}
           @streaming.processStream [ chunk ], cb # TODO: better passing of chunk
-          rowCount++
-        , {parallel: 1})
+          rowCount = rowCount + chunkSize
+        , {parallel: chunkSize})

       console.log @streaming.summaryReport


fix bug

fix bug

--- src/coffee/smart-layout.coffee
+++ src/coffee/smart-layout.coffee
@@ -70,8 +70,7 @@
                 spliter.elem.html '
<svg><path /></svg>
'
                 spliter.collapse = spliter.elem.children()
                 spliter.collapse.css @sizeType.begin, '50%'
-                spliter.collapse.css @sizeType.osize, "#{spliter.size * 4}px"
-                spliter.collapse.find('svg').css 'height', "#{spliter.size * 4}px"
+                spliter.collapse.find('svg').css @sizeType.osize, "#{spliter.size * 4}px"
                 spliter.collapse.css "margin-#{@sizeType.begin}", "-#{spliter.size * 2}px"
                 @setCollapseStyle(spliter.collapse, spliter.size, @layoutDirection, spliter.collapseDirection)
                 spliter.collapse.find('path').css 'fill', spliter.collapseColor
@@ -115,7 +114,8 @@
           next = @items[spliter.nextItemIdx]
           rawSizeBoth = pre.size + next.size
           if spliter.collapsed
-            pre.size += rawSizeBoth * spliter.preDivBoth
+            pre.size = rawSizeBoth * spliter.preDivBoth
+            console.log pre.size
           else
             if spliter.collapseDirection is 'pre'
               pre.size = pre.minSize


Add $ and ^ to visual mode

Add $ and ^ to visual mode

--- keymaps/vim-mode.cson
+++ keymaps/vim-mode.cson
@@ -22,6 +22,8 @@
   'y': 'vim-mode:yank'
   '>': 'vim-mode:indent'
   '<': 'vim-mode:outdent'
+  '$': 'vim-mode:move-to-last-character-of-line'
+  '^': 'vim-mode:move-to-first-character-of-line'

 '.vim-mode.command-mode:not(.mini)':
   'i': 'vim-mode:activate-insert-mode'


use default export

use default export

--- src/main.iced
+++ src/main.iced
@@ -23,7 +23,7 @@
     when "configure"
       await require('./configure').run(argv, defer(err))
     when "blogs"
-      await require('./blogs').run(argv, defer(err))
+      await require('./blogs')(argv, defer(err))
     when "pages"
       await require('./pages').run(argv, defer(err))
     when "products"


Improve findUsersByUsernamesWithHighlights query

--- packages/rocketchat-lib/server/models/Users.coffee
+++ packages/rocketchat-lib/server/models/Users.coffee
@@ -82,7 +82,7 @@
 	findUsersByUsernamesWithHighlights: (usernames, options) ->
 		query =
 			username: { $in: usernames }
-			'settings.preferences.highlights':
+			'settings.preferences.highlights.0':
 				$exists: true

 		return @find query, options


Fix oAuth

Fix oAuth

--- packages/rocketchat-lib/server/models/Users.coffee
+++ packages/rocketchat-lib/server/models/Users.coffee
@@ -88,7 +88,7 @@
 			$set: {}

 		serviceIdKey = "services.#{serviceName}.id"
-		update.$set[serviceIdKey] = serviceData.id
+		update.$set[serviceIdKey] = serviceId

 		return @update _id, update


Fixed current_user bug and filtering out yourself.

--- picoCTF-web/web/coffee/classroom-management.coffee
+++ picoCTF-web/web/coffee/classroom-management.coffee
@@ -108,7 +108,7 @@
 MemberManagement = React.createClass
   render: ->
     allMembers = update @props.teacherInformation, {$push: @props.memberInformation}
-    allMembers = _.without allMembers, ((member) -> @props.currentUser["tid"] != member["tid"]).bind this
+    allMembers = _.filter allMembers, ((member) -> @props.currentUser["tid"] != member["tid"]).bind this

     memberInformation = <ListGroup>
         {allMembers.map ((member, i) ->
@@ -142,7 +142,7 @@

     apiCall "GET", "/api/user/status"
     .done ((resp) ->
-      @setState update @state, $set: resp.data
+      @setState update @state, current_user: $set: resp.data
     ).bind this

     apiCall "GET", "/api/group/member_information", {gid: @props.gid}


fix indentation for children

fix indentation for children

--- src/format-issues.coffee
+++ src/format-issues.coffee
@@ -1,7 +1,7 @@
 table = require 'table-b'

 formatChild = ({ user, repo, number, title, url }) ->
-  ["    #{user}/#{repo}\##{number}", title, url]
+  ["    #{user}/#{repo}\##{number}", '    ' + title, '    ' + url]

 module.exports = (issues, root) ->
   rows = issues


Fixed coffee indentaion.

Fixed coffee indentaion.

--- src/controllers/netflix.coffee
+++ src/controllers/netflix.coffee
@@ -7,9 +7,7 @@
 browser = new Browser

 module.exports =
-	search: (req, res) ->
-		url = BASE_SEARCH_URL + encodeURIComponent(req.body.searchTerm)
-		commander.exec(
-      browser.buildCommand(url, browserFlags)
-    )
+  search: (req, res) ->
+    url = BASE_SEARCH_URL + encodeURIComponent(req.body.searchTerm)
+    commander.exec(browser.buildCommand(url, browserFlags))
     res.redirect "/"


Client is a real object
(still needs testing)

also: moved examples to the top (so that they show up early on the docco page)

--- lib/esl.coffee
+++ lib/esl.coffee
@@ -40,6 +40,51 @@
 #

 exports.debug = false
+
+#### Client Example
+# The following code does the equivalent of "fs_cli -x".
+#
+#     esl = require 'esl'
+#
+#     # Open connection, send arbitrary API command, disconnect.
+#     fs_command = (cmd,cb) ->
+#       client = esl.createClient()
+#       client.on 'esl_auth_request', (req,res) ->
+#         res.auth 'ClueCon', (req,res) ->
+#           res.api cmd, (req,res) ->
+#             res.exit ->
+#               client.end()
+#       if cb?
+#         client.on 'close', cb
+#       client.connect(8021, '127.0.0.1')
+#
+#     # Example
+#     fs_command "reloadxml"
+#
+#  Note: Use
+#
+#     res.event_json 'HEARTBEAT'
+#
+#  to start receiving event notifications.
+
+#### CallServer Example
+#
+#     server = new esl.CallServer()
+#
+#     server.on 'CONNECT', (req,res) ->
+#       # Start processing the call
+#       # Channel data is available as req.channel_data
+#       # For example:
+#       uri = req.channel_data.variable_sip_req_uri
+#
+#     # Other FreeSwitch channel events are available as well:
+#     server.on 'CHANNEL_ANSWER', (req,res) ->
+#       util.log 'Call was answered'
+#     server.on 'CHANNEL_HANGUP_COMPLETE', (req,res) ->
+#       # Call was disconnected.
+#
+#     server.listen port
+#

 #### Headers parser
 # ESL framing contains headers and a body.
@@ -374,32 +419,6 @@

 exports.createClient = () -> return new eslClient()

-#### Client Example
-# The following code does the equivalent of "fs_cli -x".
-#
-#     esl = require 'esl'
-#
-#     # Open connection, send arbitrary API command, disconnect.
-#     fs_command = (cmd,cb) ->
-#       client = esl.createClient()
-#       client.on 'esl_auth_request', (req,res) ->
-#         res.auth 'ClueCon', (req,res) ->
-#           res.api cmd, (req,res) ->
-#             res.exit ->
-#               client.end()
-#       if cb?
-#         client.on 'close', cb
-#       client.connect(8021, '127.0.0.1')
-#
-#     # Example
-#     fs_command "reloadxml"
-#
-#  Note: Use
-#
-#     res.event_json 'HEARTBEAT'
-#
-#  to start receiving event notifications.
-
 #### CallServer: a higher-level interface
 #
 # This interface is based on my
@@ -408,13 +427,13 @@

 exports.CallServer = class CallServer extends require('events').EventEmitter

-  constructor: (port) ->
+  constructor: ->

     super()

     Unique_ID = 'Unique-ID'

-    server = new eslServer (res) ->
+    @server = new eslServer (res) =>
       res.connect (req,res) =>
         # Channel data
         channel_data = req.body
@@ -437,33 +456,16 @@
         res.on 'esl_event', (req,res) =>
           req.channel_data = channel_data
           req.unique_id = unique_id
-          server.emit req.body['Event-Name'], req, res
+          @emit req.body['Event-Name'], req, res

         # Handle the incoming connection
-        res.linger (req,res) ->
-          res.filter Unique_ID, unique_id, (req,res) ->
-            res.event_json 'ALL', (req,res) ->
+        res.linger (req,res) =>
+          res.filter Unique_ID, unique_id, (req,res) =>
+            res.event_json 'ALL', (req,res) =>
               req.channel_data = channel_data
               req.unique_id = unique_id
-              server.emit 'CONNECT', req, res
-
-    # Start the server.
-    server.listen port
-    return server
-
-#### Usage:
-#
-#     server = new esl.CallServer (port)
-#
-#     server.on 'CONNECT', (req,res) ->
-#       # Start processing the call
-#       # Channel data is available as req.channel_data
-#       # For example:
-#       uri = req.channel_data.variable_sip_req_uri
-#
-#     # Other FreeSwitch channel events are available as well:
-#     server.on 'CHANNEL_ANSWER', (req,res) ->
-#       util.log 'Call was answered'
-#     server.on 'CHANNEL_HANGUP_COMPLETE', (req,res) ->
-#       # Call was disconnected.
-#
+              @emit 'CONNECT', req, res
+
+    return @
+
+  listen: -> @server.listen arguments...


Use id factory for dispatcher.

Use id factory for dispatcher.

--- src/dispatcher.coffee
+++ src/dispatcher.coffee
@@ -5,9 +5,7 @@
   @isDispatching = false
   @payload = null

-prefix = 'Dispatcher_ID_'
-lastId = 1
-nextId = -> prefix + lastId++
+dispatcherIds = new IdFactory('Dispatcher_ID')

 Dispatcher.prototype.register = ->
   args = _.compact(arguments)
@@ -18,7 +16,7 @@
     [store, action, prereqStores, callback] = args
     @callbacksByAction[action] ?= {}

-    id = nextId()
+    id = dispatcherIds.next()
     @callbacksByAction[action][id] = {
       callback: callback,
       prerequisites: _.map(prereqStores,


fix bug in gulpfile

fix bug in gulpfile

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -131,7 +131,7 @@
 # Rerun tasks when files changes
 gulp.task 'watch', ->
   # technically, adding css plugin files could cause need to redo html..
-  gulp.watch 'assets/html/**/*', ['html']
+  gulp.watch 'assets/html/**/*', ['html:dev']

   gulp.watch 'vendor/**/*', ['vendor']


fix(build): Commit correct files on tag.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -99,8 +99,8 @@
 		.pipe bump type: importance
 		# save it back to filesystem
 		.pipe gulp.dest './'
-tagVersion = ->
-	gulp.src ['./package.json']
+gulp.task 'tagversion', ->
+	gulp.src ['./package.json','./bower.json','./dist/*']
 		# commit the changed version number
 		.pipe git.commit 'chore(release): Bump Version Number'
 		# **tag it in the repository**
@@ -114,23 +114,23 @@
 	runSequence(
 		'release:prerel'
 		, 'compile'
-		, tagVersion()
+		, 'tagversion'
 	)
 gulp.task 'patch', ->
 	runSequence(
 		'release:patch'
 		, 'compile'
-		, tagVersion()
+		, 'tagversion'
 	)
 gulp.task 'minor', ->
 	runSequence(
 		'release:minor'
 		, 'compile'
-		, tagVersion()
+		, 'tagversion'
 	)
 gulp.task 'major', ->
 	runSequence(
 		'release:major'
 		, 'compile'
-		, tagVersion()
+		, 'tagversion'
 	)


April joke ;-)

April joke ;-)

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -202,12 +202,10 @@
 gulp.task 'concatScripts', ->
   src = if args.stage then [
     'bower_components/react/react.min.js'
-    'bower_components/jquery/dist/jquery.min.js'
     'client/app/build/app.js'
   ]
   else [
     'bower_components/react/react.js'
-    'bower_components/jquery/dist/jquery.js'
   ]
   gulp.src src
     .pipe concat 'app.js'


Error logging for build script to prevent breaking watch

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -39,7 +39,7 @@

 styles = ->
 	gulp.src STYLES_GLOB
-		.pipe less()
+		.pipe less().on 'error', gutil.log
 		.pipe concat 'bundle.css'
 		.pipe gulp.dest BUILD_FOLDER

@@ -70,7 +70,7 @@

 markup = ->
 	gulp.src MARKUP_GLOB
-		.pipe jade pretty: true
+		.pipe jade(pretty: true).on 'error', gutil.log
 		.pipe htmlreplace
 			styles: 'bundle.css'
 			scripts: 'bundle.js'


Minor renaming in gulpfile.

Minor renaming in gulpfile.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -273,7 +273,7 @@
   options.compilerFlags.externs.push nodeJsExterns...
   compile 'server/app/build', options

-gulp.task 'js', (callback) ->
+gulp.task 'js', (done) ->
   sequence = []
   sequence.push 'deps' if closureDeps.changed changedFilePath
   sequence.push 'unitTests', 'diContainer', 'concatDeps'
@@ -283,17 +283,17 @@
   ] if args.stage
   sequence.push 'concatScripts'
   sequence.push 'livereload-notify' if changedFilePath && !args.stage
-  sequence.push callback
+  sequence.push done
   runSequence sequence...

-gulp.task 'build', (callback) ->
+gulp.task 'build', (done) ->
   runSequence [
     'clean'
     'stylus'
     'coffee'
     'react'
     'js'
-    callback
+    done
   ]...

 gulp.task 'env', ->
@@ -320,11 +320,11 @@
       else changedFilePath = null
   watch.start()

-gulp.task 'run', (callback) ->
-  runSequence 'env', 'livereload-server', 'watch', 'server', callback
-
-gulp.task 'default', (callback) ->
-  runSequence 'build', 'run', callback
+gulp.task 'run', (done) ->
+  runSequence 'env', 'livereload-server', 'watch', 'server', done
+
+gulp.task 'default', (done) ->
+  runSequence 'build', 'run', done

 gulp.task 'bump', (done) ->
   gulp.src paths.packages


no need to explicitly enforce height since we always have <br>

--- src/editor.coffee
+++ src/editor.coffee
@@ -47,7 +47,6 @@
         margin: 0px;
         padding: 10px;
       }
-      .line { min-height: 15px; }
       a { text-decoration: underline; }
       b { font-weight: bold; }
       i { font-style: italic; }


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine.coffee
+++ src/engine.coffee
@@ -117,7 +117,7 @@
         window.requestAnimationFrame(animLoop)

     update = ->
-      window.updateKeys()
+      window.updateKeys?()

       self.trigger "update"

@@ -260,7 +260,7 @@
     self.attrAccessor "ambientLight", "backgroundColor", "cameraTransform", "clear"
     self.include Bindable

-    defaultModules = ["Shadows", "HUD", "Developer", "SaveState", "Selector", "Collision", "Tilemap", "FPSCounter"]
+    defaultModules = ["SaveState", "Selector", "Collision", "FPSCounter"]
     modules = defaultModules.concat(I.includedModules)
     modules = modules.without([].concat(I.excludedModules))


remove leading zeros of tool code. fixes #5

--- src/gerber-parser.coffee
+++ src/gerber-parser.coffee
@@ -31,8 +31,11 @@
   parseToolDef: (p, c) ->
     unless c.tool? then c.tool = {}
     code = p.match(/^ADD\d{2,}/)?[0][2..]
+    # get the shape and modifiers
     [shape, mods] = p[2+code.length..].split ','
     mods = mods?.split 'X'
+    # remove leading zeros from tool code
+    code = code[0] + code[2..] while code[1] is '0'
     switch shape
       # circle
       when 'C'


added support for tailing multiple servers at once

--- lib/log.coffee
+++ lib/log.coffee
@@ -6,7 +6,7 @@
   constructor: (@options = {}) ->

   isRemote: ->
-    @options.server?
+    @options.server? or @options.servers?

   getSshCommand: ->
     user = if @options.username? then "#{@options.username}@" else ''
@@ -37,9 +37,17 @@
       process.stdout.write data

   tailRemote: ->
+    if @options.server?
+      @_tailSingleRemote(@options.server)
+    else
+      for server in @options.servers
+        @_tailSingleRemote(server, true)
+
+
+  _tailSingleRemote: (server) ->
     c = new Connection()
     c.on 'ready', =>
-      console.log "Connected"
+      console.log "Connected to #{server}"
       cmd = @getTailCommand()
       c.exec cmd, (err, stream) =>
         stream.on 'data', (data, extended) =>
@@ -49,7 +57,7 @@
             data = @options.highlighter.highlight(data)
           process.stdout.write data
     c.connect
-      host: @options.server
+      host: server
       port: @options.port or 22
       username: @options.username or nil
       agent: process.env['SSH_AUTH_SOCK']