activity: move reactivityRoutes to module scope

--- client/activity/lib/routehandler.coffee
+++ client/activity/lib/routehandler.coffee
@@ -7,24 +7,24 @@
 isReactivityEnabled       = require 'app/util/isReactivityEnabled'
 { RoutingContext, match } = require 'react-router'

+reactivityRouteTypes = [
+  'SingleChannel'
+  'SinglePost'
+  'SingleChannelWithSummary'
+  'SinglePostWithSummary'
+  'PrivateMessages'
+]
+
 module.exports = -> lazyrouter.bind 'activity', (type, info, state, path, ctx) ->

   handle = (name) -> handlers["handle#{name}"](info, ctx, path, state)
-
-  reactivityRoutes = [
-    'SingleChannel'
-    'SinglePost'
-    'SingleChannelWithSummary'
-    'SinglePostWithSummary'
-    'PrivateMessages'
-  ]

   # since `isReactivityEnabled` flag checks roles from config,
   # wait for mainController to be ready to call `isReactivityEnabled`
   # FIXME: Remove this call before public release. ~Umut
   kd.singletons.mainController.ready ->

-    if type in reactivityRoutes
+    if type in reactivityRouteTypes
       if isReactivityEnabled()
       then handleReactivity info, ctx
       # unless reactivity is enabled redirect reactivity routes to `Public`


add Apollos resetPassword method

add Apollos resetPassword method

--- _source/packages/newspring:core/lib/apollos.coffee
+++ _source/packages/newspring:core/lib/apollos.coffee
@@ -88,3 +88,22 @@
     email: email
   ,
     callback
+
+###
+
+  Apollos.user.resetPassword
+
+  @example changes password using reset token
+
+    Apollos.user.resetPassword token, newPassword, (error) ->
+      if error
+        console.log error
+
+  @param token is the reset token emailed to the user
+  @param newPassword is what to change the password to
+  @param callback is the function that will be called with an error if so
+
+###
+Apollos.user.resetPassword = (token, newPassword, callback) ->
+
+  return Accounts.resetPassword token, newPassword, callback


set dataTable autowidth default true

set dataTable autowidth default true

--- components/dataTable/dataTable.coffee
+++ components/dataTable/dataTable.coffee
@@ -13,7 +13,7 @@
   # * Sorting
   defaultOptions =
     bJQueryUI: false
-    bAutoWidth: false
+    bAutoWidth: true
     sPaginationType: "full_numbers"
     sDom: "<\"datatable-header\"fl><\"datatable-scroll\"t><\"datatable-footer\"ip>"
     oLanguage:


payment: add a relationship to the newly created pack to the group

--- workers/social/lib/social/models/payment/pack.coffee
+++ workers/social/lib/social/models/payment/pack.coffee
@@ -34,20 +34,28 @@
         targetType  : 'JPaymentProduct'
         as          : 'plan product'

-  @create = (group, formData, callback) ->
+  @create = (groupSlug, formData, callback) ->

     { title, description } = formData
+
+    JGroup = require '../group'

     pack = new this {
       title
       description
-      group
+      group       : groupSlug
     }

     pack.save (err) ->
       return callback err  if err

-      callback null, pack
+      JGroup.one slug: groupSlug, (err, group) ->
+        return callback err  if err
+
+        group.addPack pack, (err) ->
+          return callback err  if err
+
+          callback null, pack

   @create$ = permit 'manage products',
     success: (client, formData, callback) ->


payment: flesh out JPaymentPlan#create

payment: flesh out JPaymentPlan#create

--- workers/social/lib/social/models/payment/plan.coffee
+++ workers/social/lib/social/models/payment/plan.coffee
@@ -5,7 +5,8 @@
     forceRefresh  : yes
     forceInterval : 60

-  recurly   = require 'koding-payment'
+  recurly = require 'koding-payment'
+  createId = require 'hat'

   {secure, dash}       = require 'bongo'
   {difference, extend} = require 'underscore'
@@ -50,12 +51,38 @@
       contents      : Object
       group         : String

-  @create = (formData, callback) ->
-    console.log { formData }
-    callback message: 'needs to be implemented'
+  @create = (group, formData, callback) ->
+
+    JGroup = require '../group'
+
+    { title, description, amount } = formData
+
+    plan = new this {
+      title
+      description
+      code        : createId()
+      feeMonthly  : amount * 100 # cents
+      feeInitial  : 0
+      feeInterval : 1
+    }
+
+    plan.save (err) ->
+      return callback err  if err
+
+      recurly.createPlan plan, (err) ->
+        return callback err  if err
+
+        JGroup.one slug: group, (err, group) ->
+          return callback err  if err
+
+          group.addPlan plan, (err) ->
+            return callback err  if err
+
+            callback null, plan

   @create$ = permit 'manage products',
-    success: (client, formData, callback) -> @create formData, callback
+    success: (client, formData, callback) ->
+      @create client.context.group, formData, callback

   @removeByCode = (code, callback) ->
     console.log { code }


IDEView: Fixed closing untitled file if it's empty.

--- client/ide/views/tabview/ideview.coffee
+++ client/ide/views/tabview/ideview.coffee
@@ -271,10 +271,10 @@

     appManager.tell 'IDE', 'setActiveTabView', @tabView
     appManager.tell 'IDE', 'setFindAndReplaceViewDelegate'
-
-
+
+
   openSavedFile: (file, content) ->
-
+
       pane = @tabView.getActivePane()
       if pane.data instanceof FSFile and pane.data.path is @getDummyFilePath()
         @tabView.removePane @tabView.getActivePane()
@@ -333,9 +333,12 @@
   closeUntitledFileIfNotChanged: ->

     for pane in @tabView.panes when pane
-      if pane.data instanceof FSFile and pane.data.path is @getDummyFilePath()
-        if pane.view.getValue() is ''
-          @tabView.removePane pane
+
+      isFsFile = pane.data instanceof FSFile
+      isLocal  = pane.data.path.indexOf('localfile:/') > -1
+      isEmpty  = pane.view.getValue() is ''
+
+      @tabView.removePane pane  if isFsFile and isLocal and isEmpty

   getPlusMenuItems: ->


Fix for new simple_form

Fix for new simple_form

--- app/assets/javascripts/anjlab/datepicker.js.coffee
+++ app/assets/javascripts/anjlab/datepicker.js.coffee
@@ -186,7 +186,7 @@
     }

     @isInput = @element.is('input');
-    @component = if @element.is('.date') then @element.find('.add-on') else false;
+    @component = if !@isInput && @element.is('.date') then @element.find('.add-on') else false;

     if @isInput
       @element.on {


Show notification on component reorder.

Show notification on component reorder.

--- cms/static/coffee/src/views/unit.coffee
+++ cms/static/coffee/src/views/unit.coffee
@@ -41,7 +41,12 @@
           id: unit_location_analytics

         payload = children : @components()
-        options = success : => @model.unset('children')
+        saving = new CMS.Views.Notification.Mini
+          title: gettext('Saving') + '…'
+        saving.show()
+        options = success : =>
+          @model.unset('children')
+          saving.hide()
         @model.save(payload, options)
       helper: 'clone'
       opacity: '0.5'


remove debugging from recent thing list

remove debugging from recent thing list

--- app/assets/javascripts/recent_thing_list.js.coffee
+++ app/assets/javascripts/recent_thing_list.js.coffee
@@ -1,6 +1,4 @@
-console.log("jo")
 $ ->
-  console.log('nnrec')
   NN.RecentThingList = Backbone.Collection.extend
     models: []
     model: NN.Thing
@@ -9,8 +7,6 @@
     loadFromLocalStorage: ->
       rawThings = JSON.parse(localStorage.getItem("recentThings") || "[]")
       this.reset(rawThings)
-      #for rawThing in rawThings
-      #  this.add new NN.Thing(rawThing)
     saveToLocalStorage: ->
       localStorage.setItem("recentThings", JSON.stringify(this.toJSON()))
     limitTo: (i) ->


failing spec for simple all, else causes timeout

--- spec/Thenable.coffee
+++ spec/Thenable.coffee
@@ -124,6 +124,22 @@
         chai.expect(d).to.equal exp
         done() if expected.length is 0
       t.deliver 2
+
+  describe 'with simple all', ->
+    it 'should resolve', (done) ->
+      y1 = (c, data) ->
+        Root()
+        .deliver data
+        .then 'yep-1', ->
+          1
+      t = Root()
+      .deliver {}
+      .all [y1]
+      .else (choice, e) -> # THIS ELSE CAUSES TIMEOUT!
+        console.log "FAILED!", e
+      .finally (choice, res) ->
+        chai.expect(res).to.eql [1]
+        done()

   describe 'with all & return values', ->


rewrite the grammar

rewrite the grammar

--- grammars/language-stan.cson
+++ grammars/language-stan.cson
@@ -1,138 +1,231 @@
-'name': "Stan"
-'scopeName': "source.stan"
-'fileTypes': [ "stan" ]
+'name': 'Stan'
+'scopeName': 'source.stan'
+'fileTypes': [ 'stan' ]
 'patterns': [
   {
-    include: "#comment-number-sign"
-  }
-  {
-    include: "#comment-block-comment"
-  }
-  {
-    include: "#comment-double-slash"
-  }
-  {
-    include: "#string"
-  }
-  {
-    include: "#block-declaration"
-  }
-  {
-    include: "#type"
-  }
-  {
-    include: "#keywords-control-flow"
-  }
-  {
-    include: "#keywords-other"
-  }
-  {
-    include: "#keywords-special-functions"
-  }
-  {
-    include: "#keywords-range-constraints"
-  }
-  {
-    include: "#reserved-cpp"
-  }
-  {
-    include: "#reserved-stan"
-  }
-  {
-    include: "#lp"
-  }
-  {
-    include: "#real-exp"
-  }
-  {
-    include: "#real"
-  }
-  {
-    include: "#integer"
-  }
-  {
-    include: "#illegal-variable"
-  }
-  {
-    include: "#vars"
+    'include': '#comment-number-sign'
+  }
+  {
+    'include': '#comment-block-comment'
+  }
+  {
+    'include': '#comment-double-slash'
+  }
+  {
+    'include': '#string'
+  }
+  {
+    'include': '#block-declaration'
+  }
+  {
+    'include': '#type'
+  }
+  {
+    'include': '#keywords-control-flow'
+  }
+  {
+    'include': '#keywords-other'
+  }
+  {
+    'include': '#keywords-special-functions'
+  }
+  {
+    'include': '#keywords-range-constraints'
+  }
+  {
+    'include': '#reserved-cpp'
+  }
+  {
+    'include': '#reserved-stan'
+  }
+  {
+    'include': '#lp'
+  }
+  {
+    'include': '#real-exp'
+  }
+  {
+    'include': '#real'
+  }
+  {
+    'include': '#integer'
+  }
+  {
+    'include': '#illegal-variable'
+  }
+  {
+    'include': '#vars'
   }
 ]
-repository:
-  "comment-double-slash":
-    match: "//.*$"
-    name: "comment.line.double-slash.stan"
-  "comment-number-sign":
-    match: "#.*$"
-    name: "comment.line.number-sign.stan"
-  "comment-block-comment":
-    begin: "/\\*"
-    end: "\\*/"
-    name: "comment.block.slashes"
-  string:
-    begin: "\""
-    end: "\""
-    name: "string.quoted.double.stan"
-    patterns: [
+'repository':
+  'comment-double-slash':
+    'match': '//.*$'
+    'name': 'comment.line.double-slash.stan'
+  'comment-number-sign':
+    'match': '#.*$'
+    'name': 'comment.line.number-sign.stan'
+  'comment-block-comment':
+    'begin': '/\\*'
+    'end': '\\*/'
+    'name': 'comment.block.slashes'
+  'string':
+    'begin': '"'
+    'end': '"'
+    'name': 'string.quoted.double.stan'
+    'patterns': [
       {
-        match: "(\\p{^ASCII}|\\p{Cntrl}|\\\\)+"
-        name: "invalid.illegal.quoted.bad-char.stan"
+        'match': '(\\p{^ASCII}|\\p{Cntrl}|\\\\)+'
+        'name': 'invalid.illegal.quoted.bad-char.stan'
       }
     ]
-  "block-declaration":
-    match: "\\b(functions|data|transformed\\s+data|parameters|transformed\\s+parameters|model|generated\\s+quantities)\\b"
-    name: "entity.name.type.stan"
-  type:
-    match: "\\b(int|real|vector|simplex|ordered|positive_ordered|row_vector|matrix|corr_matrix|cov_matrix|cholesky_factor_cov|cholesky_factor_corr|void)\\b"
-    name: "storage.type.stan"
-  "keywords-control-flow":
-    match: "\\b(for|in|while|if|else)\\b"
-    name: "keyword.control.stan"
-  "keywords-range-constraints":
-    match: "\\b(lower|upper)\\b"
-    name: "keyword.other.range.stan"
-  "keywords-special-functions":
-    match: "\\b(print|increment_log_prob|reject|integrate_ode)\\b"
-    name: "keyword.other.special-functions.stan"
-  "keywords-other":
-    match: "\\b(return)\\b"
-    name: "keyword.other.other.stan"
-  "truncation-operator":
-    match: "\\bT(?=\\s*\[)"
-    name: "keyword.other.truncation.stan"
-  "reserved-cpp":
-    match: "\\b(alignas|alignof|and|and_eq|asm|auto|bitand|bitor|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|false|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|not|not_eq|nullptr|operator|or|or_eq|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|true|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while|xor|xor_eq)\\b"
-    name: "invalid.illegal.reserved.stan"
-    comment: "reserved words in C++ that are invalid in Stan"
-  "reserved-stan":
-    match: "\\b(for|in|while|repeat|until|if|then|else|true|false|var|fvar|STAN_MAJOR|STAN_MINOR|STAN_PATCH|STAN_MATH_MAJOR|STAN_MATH_MINOR|STAN_MATH_PATCH)\\b"
-    name: "invalid.illegal.reserved.stan"
-    comment: "Words reserved for internal Stan use"
-  lp:
-    match: "\\blp__\\b"
-    name: "invalid.deprecated.lp.stan"
-  constants:
-    match: "\\b(pi|e|sqrt2|log2|log10|not_a_number|positive_infinity|negative_infinity|epsilon|negative_epsilon)\\b"
-    name: "support.constant.stan"
-  functions:
-    match: "\\b(exp_mod_normal_cdf|sort_asc|gamma_log|gumbel_cdf|max|lbeta|dot_product|segment|softmax|neg_binomial_2_rng|beta_binomial_cdf_log|inv_chi_square_rng|round|poisson_ccdf_log|beta_cdf_log|gumbel_log|exponential_cdf|beta_log|bernoulli_ccdf_log|normal_ccdf_log|pareto_cdf_log|fabs|mean|diag_pre_multiply|uniform_ccdf_log|neg_binomial_2_log|expm1|gamma_rng|inv_gamma_log|lognormal_cdf|scaled_inv_chi_square_log|pareto_type_2_log|bernoulli_cdf|atanh|row|weibull_cdf_log|cumulative_sum|multinomial_log|inv_gamma_cdf_log|rayleigh_cdf|rep_row_vector|inv_wishart_rng|double_exponential_cdf_log|binomial_cdf_log|rising_factorial|multinomial_rng|sub_row|tcrossprod|lkj_corr_cholesky_log|trunc|chi_square_rng|int_step|quad_form_diag|determinant|Phi|trace|skew_normal_cdf|neg_binomial_2_cdf_log|uniform_cdf|student_t_rng|digamma|fmin|dot_self|size|atan|log_rising_factorial|multi_gp_cholesky_log|log1p_exp|cosh|inv_gamma_rng|multi_normal_cholesky_log|fma|neg_binomial_ccdf_log|scaled_inv_chi_square_cdf|trigamma|bernoulli_log|poisson_log_log|uniform_log|exp_mod_normal_ccdf_log|columns_dot_self|mdivide_right_tri_low|pareto_type_2_rng|columns_dot_product|csr_extract_w|skew_normal_log|append_row|multi_student_t_log|inv_logit|binomial_coefficient_log|gamma_p|gamma_q|asin|scaled_inv_chi_square_rng|poisson_cdf_log|multi_normal_prec_log|trace_quad_form|bernoulli_cdf_log|logistic_cdf|logistic_rng|is_inf|inv_gamma_ccdf_log|pareto_ccdf_log|quad_form_sym|gamma_cdf_log|skew_normal_cdf_log|gaussian_dlm_obs_log|log_inv_logit|tanh|dims|append_col|eigenvalues_sym|neg_binomial_log|floor|rayleigh_rng|inv_chi_square_cdf|bernoulli_logit_log|hypergeometric_rng|Phi_approx|quad_form|exp_mod_normal_cdf_log|mdivide_left_tri_low|tan|to_matrix|frechet_log|inverse|step|categorical_rng|skew_normal_rng|cos|cbrt|weibull_rng|fmax|acos|col|normal_cdf|to_array_2d|exponential_rng|pareto_type_2_cdf|multiply_log|log1m|poisson_log_rng|multi_normal_log|gumbel_ccdf_log|lkj_corr_rng|pareto_cdf|bessel_first_kind|binomial_ccdf_log|pareto_type_2_cdf_log|poisson_rng|rep_array|ceil|student_t_cdf_log|multi_normal_cholesky_rng|dirichlet_log|to_vector|sin|csr_to_dense_matrix|inv|log_sum_exp|neg_binomial_cdf_log|pareto_type_2_ccdf_log|normal_log|qr_Q|beta_cdf|log_diff_exp|ordered_logistic_log|block|pow|neg_binomial_2_log_log|eigenvectors_sym|gumbel_rng|bernoulli_rng|categorical_log|lognormal_rng|num_elements|rayleigh_ccdf_log|multi_student_t_rng|diag_matrix|singular_values|lkj_corr_log|sqrt|frechet_cdf_log|rayleigh_log|lognormal_log|beta_binomial_cdf|neg_binomial_2_cdf|beta_binomial_ccdf_log|binomial_rng|sd|variance|cauchy_rng|cauchy_log|neg_binomial_2_log_rng|skew_normal_ccdf_log|log_softmax|cauchy_cdf_log|exp2|beta_ccdf_log|weibull_cdf|squared_distance|normal_cdf_log|von_mises_log|erfc|rank|gamma_cdf|square|student_t_cdf|chi_square_cdf|inv_phi|wishart_rng|modified_bessel_first_kind|uniform_cdf_log|acosh|log_mix|sort_indices_desc|multi_normal_rng|inv_square|chi_square_cdf_log|owens_t|normal_rng|if_else|inv_wishart_log|log|rayleigh_cdf_log|hypot|double_exponential_rng|to_array_1d|exp_mod_normal_log|pareto_rng|double_exponential_cdf|distance|csr_extract_v|chi_square_ccdf_log|log_falling_factorial|binomial_logit_log|inv_chi_square_cdf_log|crossprod|asinh|fmod|scaled_inv_chi_square_ccdf_log|beta_binomial_log|logistic_cdf_log|log1m_exp|frechet_rng|abs|binomial_log|inv_cloglog|rep_matrix|multiply_lower_tri_self_transpose|diag_post_multiply|neg_binomial_cdf|logit|log10|student_t_log|wiener_log|double_exponential_log|gamma_ccdf_log|inv_chi_square_ccdf_log|fdim|to_row_vector|tail|double_exponential_ccdf_log|diagonal|lmgamma|erf|exp|frechet_cdf|poisson_cdf|pareto_log|exp_mod_normal_rng|student_t_ccdf_log|sort_desc|von_mises_rng|tgamma|gumbel_cdf_log|lognormal_cdf_log|weibull_log|prod|head|cols|cauchy_ccdf_log|qr_R|dirichlet_rng|chi_square_log|trace_gen_quad_form|rows|wishart_log|beta_rng|bessel_second_kind|csr_matrix_times_vector|beta_binomial_rng|log1p|sinh|exponential_cdf_log|sum|exponential_log|categorical_logit_log|neg_binomial_2_ccdf_log|atan2|inv_gamma_cdf|scaled_inv_chi_square_cdf_log|inv_chi_square_log|neg_binomial_rng|rows_dot_self|uniform_rng|log_determinant|csr_extract_u|lkj_corr_cholesky_rng|cauchy_cdf|log1m_inv_logit|hypergeometric_log|cholesky_decompose|multi_gp_log|exponential_ccdf_log|log2|modified_bessel_second_kind|poisson_log|binary_log_loss|lgamma|min|sub_col|weibull_ccdf_log|logistic_ccdf_log|is_nan|inv_sqrt|rows_dot_product|inverse_spd|lognormal_ccdf_log|logistic_log|frechet_ccdf_log|falling_factorial|rep_vector|ordered_logistic_rng|binomial_cdf|sort_indices_asc)\\b"
-    name: "support.function.function.stan"
-  distributions:
-    match: "\\b(bernoulli|bernoulli_logit|beta|beta_binomial|binomial|binomial_logit|categorical|categorical_logit|cauchy|chi_square|dirichlet|double_exponential|exp_mod_normal|exponential|frechet|gamma|gaussian_dlm_obs|gumbel|hypergeometric|inv_chi_square|inv_gamma|inv_wishart|lkj_corr|lkj_corr_cholesky|logistic|lognormal|multi_gp|multi_gp_cholesky|multi_normal|multi_normal_cholesky|multi_normal_prec|multi_student_t|multinomial|neg_binomial|neg_binomial_2|neg_binomial_2_log|normal|ordered_logistic|pareto|pareto_type_2|poisson|poisson_log|rayleigh|scaled_inv_chi_square|skew_normal|student_t|uniform|von_mises|weibull|wiener|wishart)\\b"
-    name: "support.function.distribution.stan"
-  vars:
-    match: "\\b[a-zA-Z][a-zA-Z0-9_]*\\b"
-    name: "variable.other.stan"
-  "illegal-variable":
-    match: "\\b([a-zA-Z0-9_]*__|[0-9_][A-Za-z0-9_]+|_)\\b"
-    name: "invalid.illegal.variable"
-  "real":
-    match: "-?(\\d+\\.(\\d+)?|\\.\\d+)\\b"
-    comment: "have a point with numbers before, maybe an exponent"
-    name: "constant.numeric.real.stan"
-  "real-exp":
-    match: "-?(\\d+(\\.\\d*)?|\\.\\d+)[eE]-?\\d+\\b"
-    comment: "no point, have an exponent"
-    name: "constant.numeric.real.stan"
-  integer:
-    match: "-?\\d+\\b"
-    name: "constant.numeric.integer.stan"
+  'block':
+    'begin': "\\{"
+    'end': "\\}"
+  'functions_block':
+    'begin': '^\\s*(functions)\\s*\\{'
+    'end': '\\}'
+    'beginCaptures':
+      '1':
+        'name': 'entity.name.type.stan'
+    'name': 'meta.block.functions.stan'
+  'data_block':
+    'begin': '^\\s*(data)\\s*\\{'
+    'end': '\\}'
+    'beginCaptures':
+      '1':
+        'name': 'entity.name.type.stan'
+    'name': 'meta.block.data.stan'
+  'transformed_data_block':
+    'begin': '^\\s*(transformed\\s*data)\\s*\\{'
+    'end': '\\}'
+    'beginCaptures':
+      '1':
+        'name': 'entity.name.type.stan'
+    'name': 'meta.block.transformeddata.stan'
+  'parameters_block':
+    'begin': '^\\s*(parameters)\\s*\\{'
+    'end': '\\}'
+    'beginCaptures':
+      '1':
+        'name': 'entity.name.type.stan'
+    'name': 'meta.block.parameters.stan'
+  'transformed_parameters_block':
+    'begin': '^\\s*(transformed\\s*parameters)\\s*\\{'
+    'end': '\\}'
+    'beginCaptures':
+      '1':
+        'name': 'entity.name.type.stan'
+    'name': 'meta.block.transformedparameters.stan'
+  'model_block':
+    'begin': '^\\s*(model)\\s*\\{'
+    'end': '\\}'
+    'beginCaptures':
+      '1':
+        'name': 'entity.name.type.stan'
+    'name': 'meta.block.model.stan'
+  'generated_quantities_block':
+    'begin': '^\\s*(generated_quantities)\\s*\\{'
+    'end': '\\}'
+    'beginCaptures':
+      '1':
+        'name': 'entity.name.type.stan'
+    'name': 'meta.block.generatedquantities.stan'
+
+  'basic_type':
+    'match': '\\b(int|real|vector|row_vector|matrix)\\b'
+    'name': 'storage.type.basic.stan'
+  'type':
+    'match': '\\b(\\b'
+    'name': 'storage.type.declaration.stan'
+  'function_declaration':
+    'begin': '(?x)
+      \\b
+      (void|int|real|vector|row_vector|matrix)
+      \\s+
+      ([A-Za-z][A-Za-z0-9_]*)
+      \\s*
+      \\(
+      \\b
+    '
+    'beginCaptures':
+      '1':
+        'name': 'storage.type.return.stan'
+      '2':
+        'name': 'entity.name.function.stan'
+    'end': '\\)'
+    'name': 'storage.type.return.stan'
+    'comment': 'type function( ... )'
+    'patterns': [
+      {
+        'include': '#basic_type'
+      }
+    ]
+  'variable_declaration':
+    'pattern': '(?x)
+      \\b
+      (int|real|vector|simplex|ordered|positive_ordered|row_vector|matrix|corr_matrix|cov_matrix|cholesky_factor_cov|cholesky_factor_corr|void)
+      \\s*
+      (?:<.*>)?
+      \\s
+      [.*]?
+      \\s+
+      ([A-Za-z][A-Za-z0-9_]*)
+      [.*]?
+      \\s*
+      ;
+    '
+    'captures':
+      '1':
+        'storage.type.variable.stan'
+      '2':
+        'entity.variable.stan'
+    'comment': 'type<bounds>[dim] variables[dim];'
+  'keywords-control-flow':
+    'match': '\\b(for|in|while|if|else)\\b'
+    'name': 'keyword.control.stan'
+  'keywords-range-constraints':
+    'match': '\\b(lower|upper)\\b'
+    'name': 'keyword.other.range.stan'
+  'keywords-special-functions':
+    'match': '\\b(print|increment_log_prob|reject|integrate_ode)\\b'
+    'name': 'keyword.other.special-functions.stan'
+  'keywords-other':
+    'match': '\\b(return)\\b'
+    'name': 'keyword.other.other.stan'
+  'truncation-operator':
+    'match': '\\bT(?=\\s*\[)'
+    'name': 'keyword.other.truncation.stan'
+  'reserved-cpp':
+    'match': '\\b(alignas|alignof|and|and_eq|asm|auto|bitand|bitor|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|false|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|not|not_eq|nullptr|operator|or|or_eq|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|true|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while|xor|xor_eq)\\b'
+    'name': 'invalid.illegal.reserved.stan'
+    'comment': 'reserved words in C++ that are invalid in Stan'
+  'reserved-stan':
+    'match': '\\b(for|in|while|repeat|until|if|then|else|true|false|var|fvar|STAN_MAJOR|STAN_MINOR|STAN_PATCH|STAN_MATH_MAJOR|STAN_MATH_MINOR|STAN_MATH_PATCH)\\b'
+    'name': 'invalid.illegal.reserved.stan'
+    'comment': 'Words reserved for internal Stan use'
+  'lp':
+    'match': '\\blp__\\b'
+    'name': 'invalid.deprecated.lp.stan'
+  'constants':
+    'match': '\\b(pi|e|sqrt2|log2|log10|not_a_number|positive_infinity|negative_infinity|epsilon|negative_epsilon)\\b'
+    'name': 'support.constant.stan'
+  'functions':
+    'match': '\\b(exp_mod_normal_cdf|sort_asc|gamma_log|gumbel_cdf|max|lbeta|dot_product|segment|softmax|neg_binomial_2_rng|beta_binomial_cdf_log|inv_chi_square_rng|round|poisson_ccdf_log|beta_cdf_log|gumbel_log|exponential_cdf|beta_log|bernoulli_ccdf_log|normal_ccdf_log|pareto_cdf_log|fabs|mean|diag_pre_multiply|uniform_ccdf_log|neg_binomial_2_log|expm1|gamma_rng|inv_gamma_log|lognormal_cdf|scaled_inv_chi_square_log|pareto_type_2_log|bernoulli_cdf|atanh|row|weibull_cdf_log|cumulative_sum|multinomial_log|inv_gamma_cdf_log|rayleigh_cdf|rep_row_vector|inv_wishart_rng|double_exponential_cdf_log|binomial_cdf_log|rising_factorial|multinomial_rng|sub_row|tcrossprod|lkj_corr_cholesky_log|trunc|chi_square_rng|int_step|quad_form_diag|determinant|Phi|trace|skew_normal_cdf|neg_binomial_2_cdf_log|uniform_cdf|student_t_rng|digamma|fmin|dot_self|size|atan|log_rising_factorial|multi_gp_cholesky_log|log1p_exp|cosh|inv_gamma_rng|multi_normal_cholesky_log|fma|neg_binomial_ccdf_log|scaled_inv_chi_square_cdf|trigamma|bernoulli_log|poisson_log_log|uniform_log|exp_mod_normal_ccdf_log|columns_dot_self|mdivide_right_tri_low|pareto_type_2_rng|columns_dot_product|csr_extract_w|skew_normal_log|append_row|multi_student_t_log|inv_logit|binomial_coefficient_log|gamma_p|gamma_q|asin|scaled_inv_chi_square_rng|poisson_cdf_log|multi_normal_prec_log|trace_quad_form|bernoulli_cdf_log|logistic_cdf|logistic_rng|is_inf|inv_gamma_ccdf_log|pareto_ccdf_log|quad_form_sym|gamma_cdf_log|skew_normal_cdf_log|gaussian_dlm_obs_log|log_inv_logit|tanh|dims|append_col|eigenvalues_sym|neg_binomial_log|floor|rayleigh_rng|inv_chi_square_cdf|bernoulli_logit_log|hypergeometric_rng|Phi_approx|quad_form|exp_mod_normal_cdf_log|mdivide_left_tri_low|tan|to_matrix|frechet_log|inverse|step|categorical_rng|skew_normal_rng|cos|cbrt|weibull_rng|fmax|acos|col|normal_cdf|to_array_2d|exponential_rng|pareto_type_2_cdf|multiply_log|log1m|poisson_log_rng|multi_normal_log|gumbel_ccdf_log|lkj_corr_rng|pareto_cdf|bessel_first_kind|binomial_ccdf_log|pareto_type_2_cdf_log|poisson_rng|rep_array|ceil|student_t_cdf_log|multi_normal_cholesky_rng|dirichlet_log|to_vector|sin|csr_to_dense_matrix|inv|log_sum_exp|neg_binomial_cdf_log|pareto_type_2_ccdf_log|normal_log|qr_Q|beta_cdf|log_diff_exp|ordered_logistic_log|block|pow|neg_binomial_2_log_log|eigenvectors_sym|gumbel_rng|bernoulli_rng|categorical_log|lognormal_rng|num_elements|rayleigh_ccdf_log|multi_student_t_rng|diag_matrix|singular_values|lkj_corr_log|sqrt|frechet_cdf_log|rayleigh_log|lognormal_log|beta_binomial_cdf|neg_binomial_2_cdf|beta_binomial_ccdf_log|binomial_rng|sd|variance|cauchy_rng|cauchy_log|neg_binomial_2_log_rng|skew_normal_ccdf_log|log_softmax|cauchy_cdf_log|exp2|beta_ccdf_log|weibull_cdf|squared_distance|normal_cdf_log|von_mises_log|erfc|rank|gamma_cdf|square|student_t_cdf|chi_square_cdf|inv_phi|wishart_rng|modified_bessel_first_kind|uniform_cdf_log|acosh|log_mix|sort_indices_desc|multi_normal_rng|inv_square|chi_square_cdf_log|owens_t|normal_rng|if_else|inv_wishart_log|log|rayleigh_cdf_log|hypot|double_exponential_rng|to_array_1d|exp_mod_normal_log|pareto_rng|double_exponential_cdf|distance|csr_extract_v|chi_square_ccdf_log|log_falling_factorial|binomial_logit_log|inv_chi_square_cdf_log|crossprod|asinh|fmod|scaled_inv_chi_square_ccdf_log|beta_binomial_log|logistic_cdf_log|log1m_exp|frechet_rng|abs|binomial_log|inv_cloglog|rep_matrix|multiply_lower_tri_self_transpose|diag_post_multiply|neg_binomial_cdf|logit|log10|student_t_log|wiener_log|double_exponential_log|gamma_ccdf_log|inv_chi_square_ccdf_log|fdim|to_row_vector|tail|double_exponential_ccdf_log|diagonal|lmgamma|erf|exp|frechet_cdf|poisson_cdf|pareto_log|exp_mod_normal_rng|student_t_ccdf_log|sort_desc|von_mises_rng|tgamma|gumbel_cdf_log|lognormal_cdf_log|weibull_log|prod|head|cols|cauchy_ccdf_log|qr_R|dirichlet_rng|chi_square_log|trace_gen_quad_form|rows|wishart_log|beta_rng|bessel_second_kind|csr_matrix_times_vector|beta_binomial_rng|log1p|sinh|exponential_cdf_log|sum|exponential_log|categorical_logit_log|neg_binomial_2_ccdf_log|atan2|inv_gamma_cdf|scaled_inv_chi_square_cdf_log|inv_chi_square_log|neg_binomial_rng|rows_dot_self|uniform_rng|log_determinant|csr_extract_u|lkj_corr_cholesky_rng|cauchy_cdf|log1m_inv_logit|hypergeometric_log|cholesky_decompose|multi_gp_log|exponential_ccdf_log|log2|modified_bessel_second_kind|poisson_log|binary_log_loss|lgamma|min|sub_col|weibull_ccdf_log|logistic_ccdf_log|is_nan|inv_sqrt|rows_dot_product|inverse_spd|lognormal_ccdf_log|logistic_log|frechet_ccdf_log|falling_factorial|rep_vector|ordered_logistic_rng|binomial_cdf|sort_indices_asc)\\b'
+    'name': 'support.function.function.stan'
+  'distributions':
+    'match': '\\b(?<=~\\s*)(bernoulli|bernoulli_logit|beta|beta_binomial|binomial|binomial_logit|categorical|categorical_logit|cauchy|chi_square|dirichlet|double_exponential|exp_mod_normal|exponential|frechet|gamma|gaussian_dlm_obs|gumbel|hypergeometric|inv_chi_square|inv_gamma|inv_wishart|lkj_corr|lkj_corr_cholesky|logistic|lognormal|multi_gp|multi_gp_cholesky|multi_normal|multi_normal_cholesky|multi_normal_prec|multi_student_t|multinomial|neg_binomial|neg_binomial_2|neg_binomial_2_log|normal|ordered_logistic|pareto|pareto_type_2|poisson|poisson_log|rayleigh|scaled_inv_chi_square|skew_normal|student_t|uniform|von_mises|weibull|wiener|wishart)\\b'
+    'name': 'support.function.distribution.stan'
+  'real':
+    'match': '-?(\\d+\\.(\\d+)?|\\.\\d+)\\b'
+    'comment': 'have a point with numbers before, maybe an exponent'
+    'name': 'constant.numeric.real.stan'
+  'real-exp':
+    'match': '-?(\\d+(\\.\\d*)?|\\.\\d+)[eE]-?\\d+\\b'
+    'comment': 'no point, have an exponent'
+    'name': 'constant.numeric.real.stan'
+  'integer':
+    'match': '-?\\d+\\b'
+    'name': 'constant.numeric.integer.stan'
+  'illegal-variable':
+    'match': '\\b([a-zA-Z0-9_]*__|[0-9_][A-Za-z0-9_]+|_)\\b'
+    'name': 'invalid.illegal.variable'


street names are very hard to see under opaque polylines, make them slightly more transparent

--- app/assets/transit/lib/models/google_map.js.coffee
+++ app/assets/transit/lib/models/google_map.js.coffee
@@ -59,7 +59,7 @@
     else new G.LatLng(arguments[0], arguments[1] ? arguments[0])

   # creates a polyline with the set of points and given color
-  create_polyline: (points, color = '#000', weight = 5, opacity = 0.8) ->
+  create_polyline: (points, color = '#000', weight = 5, opacity = 0.6) ->
     points = G.geometry.encoding.decodePath(points)
     new G.Polyline
       path: points,


Remove console.log

Remove console.log

--- app/scripts/components/entities/WaterSplash.coffee
+++ app/scripts/components/entities/WaterSplash.coffee
@@ -3,8 +3,6 @@
     @requires '2D,Canvas,Particles,Delay'

   waterSplash: (attr) ->
-    console.log attr.size
-
     options =
       maxParticles: 100
       size: attr.size / 2


Update Jasmine stacktrace formatting

Update Jasmine stacktrace formatting

--- spec/atom-reporter.coffee
+++ spec/atom-reporter.coffee
@@ -33,6 +33,8 @@
       line = line.trim()
         # at jasmine.Spec.<anonymous> (path:1:2) -> at path:1:2
         .replace(/^at jasmine\.Spec\.<anonymous> \(([^)]+)\)/, 'at $1')
+        # at jasmine.Spec.it (path:1:2) -> at path:1:2
+        .replace(/^at jasmine\.Spec\.f*it \(([^)]+)\)/, 'at $1')
         # at it (path:1:2) -> at path:1:2
         .replace(/^at f*it \(([^)]+)\)/, 'at $1')
         # at spec/file-test.js -> at file-test.js


exports empty object

exports empty object

--- desktop/components/split_test/running_tests.coffee
+++ desktop/components/split_test/running_tests.coffee
@@ -13,3 +13,5 @@
 # Note: if there are no running tests
 # this should export empty Object
 # module.exports = {}
+
+module.exports = {}


Removed FactlinkConfig

Removed FactlinkConfig

--- js-library/app/js/publisher_poc/nu.nl.coffee
+++ js-library/app/js/publisher_poc/nu.nl.coffee
@@ -6,23 +6,9 @@
   */
 (function(e,t,n){typeof module!="undefined"&&module.exports?module.exports=n():typeof define=="function"&&define.amd?define(n):t[e]=n()})("$script",this,function(){function v(e,t){for(var n=0,r=e.length;n<r;++n)if(!t(e[n]))return f;return 1}function m(e,t){v(e,function(e){return!t(e)})}function g(e,t,a){function d(e){return e.call?e():r[e]}function b(){if(!--p){r[h]=1,c&&c();for(var e in s)v(e.split("|"),d)&&!m(s[e],d)&&(s[e]=[])}}e=e[l]?e:[e];var f=t&&t.call,c=f?t:a,h=f?e.join(""):t,p=e.length;return setTimeout(function(){m(e,function(e){if(e===null)return b();if(u[e])return h&&(i[h]=1),u[e]==2&&b();u[e]=1,h&&(i[h]=1),y(!n.test(e)&&o?o+e+".js":e,b)})},0),g}function y(n,r){var i=e.createElement("script"),s=f;i.onload=i.onerror=i[d]=function(){if(i[h]&&!/^c|loade/.test(i[h])||s)return;i.onload=i[d]=null,s=1,u[n]=2,r()},i.async=1,i.src=n,t.insertBefore(i,t.firstChild)}var e=document,t=e.getElementsByTagName("head")[0],n=/^https?:\/\//,r={},i={},s={},o,u={},a="string",f=!1,l="push",c="DOMContentLoaded",h="readyState",p="addEventListener",d="onreadystatechange";return!e[h]&&e[p]&&(e[p](c,function b(){e.removeEventListener(c,b,f),e[h]="complete"},f),e[h]="loading"),g.get=y,g.order=function(e,t,n){(function r(i){i=e.shift(),e.length?g(i,r):g(i,t,n)})()},g.path=function(e){o=e},g.ready=function(e,t,n){e=e[l]?e:[e];var i=[];return!m(e,function(e){r[e]||i[l](e)})&&v(e,function(e){return r[e]})?t():!function(e){s[e]=s[e]||[],s[e][l](t),n&&n(i)}(e.join("|")),g},g.done=function(e){g([null],e)},g})
 `
-localConfig =
-  api: "http://localhost:3000"
-  lib: "http://localhost:8000/lib/dist"
-  srcPath: "/factlink.core.js"
-  url: window.location.href
-
-remoteConfig =
-  api: "https://factlink-testserver.inverselink.com:443"
-  lib: "https://factlink-static-testserver.inverselink.com:443/lib/dist"
-  srcPath: "/factlink.core.min.js"
-  url: window.location.href
-
-window.FactlinkConfig = localConfig
-
 $script(['//code.jquery.com/jquery-1.10.2.min.js',
          '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js',
-         "#{window.FactlinkConfig.lib}/factlink_loader_basic.js"
+         "#{window.FactlinkConfig.lib}/factlink_loader_basic.#{window.FactlinkConfig.minified}js"
          ], 'myBundle')

 $script.ready 'myBundle', ->


Adjust formula for fewer/less transfer modifier

[#151508724]

https://www.pivotaltracker.com/story/show/151508724

--- src/code/models/relation-factory.coffee
+++ src/code/models/relation-factory.coffee
@@ -179,11 +179,11 @@
     id: "proportionalSourceLess"
     text: tr "~NODE-RELATION-EDIT.VARIABLE_FLOW_SOURCE_LESS"
     postfixIco: "less"
-    formula: "(maxIn - in) * 0.10 + 0.001"
-    magnitude: 0
-    gradual: 0
-    func: (scope) ->
-      return (scope.maxIn - scope.in) * 0.10 + 0.001
+    formula: "(maxIn - in) * 0.10 + 0.02"
+    magnitude: 0
+    gradual: 0
+    func: (scope) ->
+      return (scope.maxIn - scope.in) * 0.10 + 0.02

   @iconName: (incdec,amount)->
     "icon-#{incdec.prefixIco}-#{amount.postfixIco}"


do some cleaning

do some cleaning

--- src/coffee/directives/controller.coffee
+++ src/coffee/directives/controller.coffee
@@ -15,17 +15,23 @@
         scope.definition = definitionService(scope.url).then((definition) ->
           scope.definition = definition.form
         )
-
-      scope.$watch('definition', (v) ->
-        console.log v
-        if v? and v.pages? then validatorService(scope)
+
+      else
+        if scope.form?
+          scope.definition = scope.form.form
+          console.log scope.form
+
+      scope.$watch('form', (v) ->
+        if v? and v.form?
+          scope.definition = scope.form.form
+          validatorService(scope)
       )

     return {
       restrict: 'E'
       scope:
         url: '@?'
-        definition: '=?'
+        form: '=?'
       template: templates.controller
       link: l
       replace: true


Store displayed sections in url for reload/sharing

--- src/components/questions/dashboard.cjsx
+++ src/components/questions/dashboard.cjsx
@@ -38,14 +38,26 @@
     courseId: React.PropTypes.string.isRequired
     ecosystemId: React.PropTypes.string.isRequired

+  contextTypes:
+    router: React.PropTypes.func
+
   getInitialState: -> {}
+
+  componentWillMount: ->
+    selectedSections = @context.router.getCurrentQuery()['sid']?.split('-')
+    if selectedSections
+      @setState(sectionIds: selectedSections, displayingIds: selectedSections)
+      ExerciseActions.loadForCourse( @props.courseId, selectedSections, '' )
+
   showQuestions: ->
     ExerciseActions.loadForCourse( @props.courseId, @state.sectionIds, '' )
-    @setState(displayingIds: @state.sectionIds)
+    @context.router.transitionTo('viewQuestionsLibrary',
+      {courseId: @props.courseId},
+      {sid: @state.sectionIds.join('-')}
+    )

   clearQuestions: -> @replaceState({sectionIds: []})
   onSectionChange: (sectionIds) -> @setState({sectionIds})
-

   render: ->
     course = CourseStore.get(@props.courseId)


Fix bug related to adding a new snapshot

--- tunemachine/public/src/playlistlist.cjsx
+++ tunemachine/public/src/playlistlist.cjsx
@@ -61,7 +61,35 @@
           type: 'tm:playlist'
           playlist: data.playlists[selected]

-    # TODO: listen to add-snapshot event
+    $('body').on 'tm:add-snapshot', (e) =>
+      # This whold function is kind of a hack because there are two sources of
+      # truth for lists of snapshots. Ideally, they'd be either all entirely
+      # managed in one place instead of both by PlaylistList and SnapshotList
+
+      # Push the new snapshot onto the current playlist
+
+      playlist = this.state.playlists[this.state.selected]
+
+      if playlist
+        operation =
+          $push: [e.snapshot]
+      else
+        operation =
+          $set: [e.snapshot]
+
+      newPlaylist = React.addons.update playlist,
+        snapshots: operation
+
+      # Set the new playlist as the real playlist
+
+      update = {}
+      update[this.state.selected] =
+        $set: newPlaylist
+
+      newState = React.addons.update this.state,
+        playlists: update
+
+      this.setState newState

   render: ->
     playlistItems = _.map this.state.playlists, (playlist, idx) =>


Use "top_left" if @mget("glyphspec").anchor gives nothing

--- bokehjs/src/coffee/renderer/glyph/image_url.coffee
+++ bokehjs/src/coffee/renderer/glyph/image_url.coffee
@@ -54,7 +54,7 @@
           @_render_image(ctx, vs, i, @image[i])

     _final_sx_sy: () ->
-      anchor = @mget('glyphspec')['anchor']
+      anchor = @mget('glyphspec').anchor or "top_left"

       switch anchor
         when "top_left"      then (i) => [@sx[i]           , @sy[i]           ]


fix documentation

fix documentation

--- jax-core/lib/assets/javascripts/jax/input.js.coffee
+++ jax-core/lib/assets/javascripts/jax/input.js.coffee
@@ -34,8 +34,8 @@

   ###
   Subclasses can override this method if they need to maintain themselves
-  over time. The default implementation does nothing. Timechange is in
-  seconds.
+  over time. They need to be sure to call `super`, in order to dispatch events
+  that have been enqueued since the last frame. Timechange is in seconds.
   ###
   update: (timechange) ->
     for type, event of @_pendingEvents


run data

run data

--- shared/ironTableController.coffee
+++ shared/ironTableController.coffee
@@ -315,10 +315,9 @@
     @_sess("recordCount")

-  #data: ->
+  data: ->
   #  console.log("ironTableController data")
   #  {}
-  ###
     theData =
       increment: @increment

@@ -336,9 +335,8 @@
       #doDownloadLink: @doDownloadLink
       #headers: @headers()
       #records: @recordsData()
-    #@fetchRecordCount()
+      #@fetchRecordCount()
     _.extend(theData, @params)
-  ###

   getRecordsName: ->
     @_recordsName()


fix autoclosing of dialogs when an area behind them is clicked

--- lib/assets/javascripts/up/modal.js.coffee
+++ lib/assets/javascripts/up/modal.js.coffee
@@ -171,12 +171,14 @@
   # (but not on a modal opener).
   up.on('click', 'body', (event, $body) ->
     $target = $(event.target)
-    unless $target.closest('.up-dialog').length || $target.closest('[up-modal]').length
+    unless $target.closest('.up-modal').length || $target.closest('[up-modal]').length
       close()
   )

   up.bus.on('fragment:ready', ($fragment) ->
     unless $fragment.closest('.up-modal').length
+      console.log('fragment inserted', $fragment, $fragment.closest('.up-modal'))
+      # alert("autoclosing due to inserted fragment")
       autoclose()
   )


Visual/edit modes: minor improvements.

Visual/edit modes: minor improvements.

--- content_scripts/mode_visual_edit.coffee
+++ content_scripts/mode_visual_edit.coffee
@@ -1,3 +1,7 @@
+
+# Todo:
+# Fix word movement, particularly for "a word".
+# Konami code?

 # This prevents printable characters from being passed through to underlying page.  It should, however, allow
 # through chrome keyboard shortcuts.  It's a backstop for all of the modes following.
@@ -280,28 +284,38 @@
       alterMethod: "extend"
     super extend defaults, options

-    extend @commands,
-      "V": -> new VisualLineMode
-      "y": ->
-        # Special case: "yy" (the first from edit mode, and now the second).
-        @selectLexicalEntity "lineboundary" if @options.yYanksLine and @keyPressCount == 1
-        @yank()
-
+    unless @options.oneMovementOnly
+      extend @commands,
+        "V": -> new VisualLineMode
+        "y": -> @yank()
+
+    # Additional commands when run under edit mode.
     if @options.editModeParent and not @options.oneMovementOnly
       extend @commands,
         "c": -> @yank deleteFromDocument: true; @options.editModeParent.enterInsertMode()
         "x": -> @yank deleteFromDocument: true
-        "d": ->
-          # Special case: "dd" (the first from edit mode, and now the second).
-          @selectLexicalEntity "lineboundary" if @options.dYanksLine and @keyPressCount == 1
+        "d": -> @yank deleteFromDocument: true
+
+    # For "yy".
+    if @options.yYanksLine
+      @commands.y = ->
+        if @keyPressCount == 1
+          @selectLexicalEntity "lineboundary"
+          @yank()
+
+    # For "dd".
+    if @options.dYanksLine
+      @commands.d = ->
+        if @keyPressCount == 1
+          @selectLexicalEntity "lineboundary"
           @yank deleteFromDocument: true

+    # For "daw", "das", "dap", "caw", "cas", "cap".
     if @options.oneMovementOnly
-      extend @commands,
-        "a": ->
-          if @keyPressCount == 1
-            for entity in [ "word", "sentence", "paragraph" ]
-              do (entity) => @movements[entity.charAt 0] = -> @selectLexicalEntity entity
+      @commands.a = ->
+        if @keyPressCount == 1
+          for entity in [ "word", "sentence", "paragraph" ]
+            do (entity) => @movements[entity.charAt 0] = -> @selectLexicalEntity entity

     unless @options.editModeParent
       @installFindMode()
@@ -395,7 +409,7 @@

 class VisualLineMode extends VisualMode
   constructor: (options = {}) ->
-    options.name = "visual/line"
+    options.name ||= "visual/line"
     super options
     unless @selection?.type == "None"
       @selectLexicalEntity "lineboundary"
@@ -427,14 +441,14 @@
       "P": -> @pasteClipboard backward
       "v": -> @launchSubMode VisualMode

-      "Y": -> @enterVisualMode runMovement: "Y"
-      "x": -> @enterVisualMode runMovement: "h", deleteFromDocument: true
-      "y": -> @enterVisualMode yYanksLine: true
-      "d": -> @enterVisualMode deleteFromDocument: true, dYanksLine: true
-      "c": -> @enterVisualMode deleteFromDocument: true, onYank: => @enterInsertMode()
-
-      "D": -> @enterVisualMode runMovement: "$", deleteFromDocument: true
-      "C": -> @enterVisualMode runMovement: "$", deleteFromDocument: true, onYank: => @enterInsertMode()
+      "Y": -> @enterVisualModeForMovement runMovement: "Y"
+      "x": -> @enterVisualModeForMovement runMovement: "h", deleteFromDocument: true
+      "y": -> @enterVisualModeForMovement yYanksLine: true
+      "d": -> @enterVisualModeForMovement deleteFromDocument: true, dYanksLine: true
+      "c": -> @enterVisualModeForMovement deleteFromDocument: true, onYank: => @enterInsertMode()
+
+      "D": -> @enterVisualModeForMovement runMovement: "$", deleteFromDocument: true
+      "C": -> @enterVisualModeForMovement runMovement: "$", deleteFromDocument: true, onYank: => @enterInsertMode()

       # Disabled as potentially confusing.
       # # If the input is empty, then enter insert mode immediately
@@ -443,13 +457,12 @@
       #     @enterInsertMode()
       #     HUD.showForDuration "Input empty, entered insert mode directly.", 3500

-  enterVisualMode: (options = {}) ->
-    defaults =
-      badge: ""
+  enterVisualModeForMovement: (options = {}) ->
+    @launchSubMode VisualMode, extend options,
+      badge: "M"
       initialCount: @countPrefix
       oneMovementOnly: true
     @countPrefix = ""
-    @launchSubMode VisualMode, extend defaults, options

   enterInsertMode: () ->
     @launchSubMode InsertMode,


Remove cors polyfill

Remove cors polyfill

--- lib/assets/javascripts/firehose/long_poll.js.coffee
+++ lib/assets/javascripts/firehose/long_poll.js.coffee
@@ -94,35 +94,3 @@
       setTimeout @_ping, @_retryDelay + @_lagTime
       # Reconnect with delay
       setTimeout @_request, @_retryDelay
-
-# Let's try to hack in support for IE8-9 via the XDomainRequest object!
-# This was adapted from code shamelessly stolen from:
-# https://github.com/jaubourg/ajaxHooks/blob/master/src/ajax/xdr.js
-if $?.browser?.msie and parseInt($.browser.version, 10) in [8, 9]
-  jQuery.ajaxTransport (s) ->
-    if s.crossDomain and s.async
-      if s.timeout
-        s.xdrTimeout = s.timeout
-        delete s.timeout
-      xdr = undefined
-      return {
-        send: (_, complete) ->
-          callback = (status, statusText, responses, responseHeaders) ->
-            xdr.onload = xdr.onerror = xdr.ontimeout = jQuery.noop
-            xdr = undefined
-            complete status, statusText, responses, responseHeaders
-          xdr = new XDomainRequest()
-          xdr.open s.type, s.url
-          xdr.onload = ->
-            headers = "Content-Type: #{xdr.contentType}"
-            callback 200, "OK", {text: xdr.responseText}, headers
-          xdr.onerror = -> callback 404, "Not Found"
-          if s.xdrTimeout?
-            xdr.ontimeout = -> callback 0, "timeout"
-            xdr.timeout   = s.xdrTimeout
-          xdr.send (s.hasContent and s.data) or null
-        abort: ->
-          if xdr?
-            xdr.onerror = jQuery.noop()
-            xdr.abort()
-      }


Fix scripts task when rollbar access token is empty

--- gulp/tasks/build/scripts.coffee
+++ gulp/tasks/build/scripts.coffee
@@ -14,7 +14,7 @@
 uploadSourcemapsToRollbar = ->
   shouldUploadRollbarSourcemaps = !!+GLOBALS.UPLOAD_SOURCEMAPS_TO_ROLLBAR && !!GLOBALS.ROLLBAR_SERVER_ACCESS_TOKEN
   gulpIf(shouldUploadRollbarSourcemaps, rollbar({
-    accessToken: (GLOBALS.ROLLBAR_SERVER_ACCESS_TOKEN ? "none")
+    accessToken: (GLOBALS.ROLLBAR_SERVER_ACCESS_TOKEN || "none")
     version: GLOBALS.CODE_VERSION
     sourceMappingURLPrefix: GLOBALS.ROLLBAR_SOURCEMAPS_URL_PREFIX + "/js"
   }))


Updated event handlers to have the original selector as this

--- source/coffee/image-picker.coffee
+++ source/coffee/image-picker.coffee
@@ -78,7 +78,7 @@
           if @selected_values().length < @opts.limit
             imagepicker_option.option.prop("selected", true)
           else if @opts.limit_reached?
-            @opts.limit_reached()
+            @opts.limit_reached.call(this.select)
         else
           imagepicker_option.option.prop("selected", true)
     else
@@ -89,7 +89,7 @@
     new_values = @selected_values()
     unless both_array_are_equal(old_values, new_values)
       @select.change()
-      @opts.changed() if @opts.changed?
+      @opts.changed.call(this.select) if @opts.changed?

 class ImagePickerOption
@@ -127,8 +127,8 @@

   clicked: () ->
     @picker.toggle(this)
-    @opts.clicked()  if @opts.clicked?
-    @opts.selected() if @opts.selected? and @is_selected()
+    @opts.clicked.call(this.picker.select)  if @opts.clicked?
+    @opts.selected.call(this.picker.select) if @opts.selected? and @is_selected()

   create_node: () ->
     @node = jQuery("<li/>")


Clean up constructor API logic and add explanatory comments to it

--- src/stochator.coffee
+++ src/stochator.coffee
@@ -163,43 +163,32 @@

     VERSION = "0.3.4"

-    constructor: (configs...) ->
-        @setGenerator(configs)
-
-    createGenerator: (config) ->
-        config.kind ?= "float"
-        generator = switch config.kind
-            when "float"
-                { min, max, mean, stdev } = config
-                floatGenerator(min, max, mean, stdev)
-            when "integer"
-                integerGenerator(config.min, config.max)
-            when "set"
-                { values, replacement, shuffle, weights } = config
-                setGenerator(values, replacement, shuffle, weights)
-            when "color", "rgb" then randomColor(config.kind)
-            when "a-z", "A-Z" then randomCharacter(config.kind is "a-z")
-        if not generator
-            throw Error("#{ config.kind } not a recognized kind.")
-        else
-            generator
-
-    createGenerators: (configs, mutator) ->
-        configs[0] ?= {}
-        generators = (@createGenerator(config) for config in configs)
-
-        if not mutator
-            callGenerators = if generators.length is 1
-                -> callFunctions(generators)[0]
+    constructor: (configs..., mutator=null, name="next") ->
+        # If the last arg is an object, all args are config args.
+        # If the penultimate arg is an object, check whether the last arg
+        # is a string (hence, the name) or a function (hence, the mutator).
+        if isObject(name)
+            configs[configs.length..configs.length + 2] = [mutator, name]
+            [mutator, name] = [null, "next"]
+        else if isObject(mutator)
+            configs[configs.length] = mutator
+            [mutator, name] = if isFunc(name)
+                [name, "next"]
             else
-                -> callFunctions(generators)
-        else
-            caller = if generators.length is 1
-                -> callFunctions(generators)[0]
-            else
-                -> callFunctions(generators)
-
-            callGenerators = => @value = mutator.call(@, caller(), @value)
+                [null, name]
+
+        # If the mutator is provided, override the default identity func.
+        if mutator
+            @mutate = (nextValue) => mutator(nextValue, @getValue())
+
+        # Transform the configs to a func to get the next value.
+        getNext = getNextValueGenerator(configs)
+
+        # Assign `name` to the next mutated value(s), after `times` iterations.
+        # If `times` is 1, just return the value, otherwise return an array.
+        @[name] = (times=1) =>
+            values = (@setValue(@mutate(getNext())) for time in [1..times])
+            if times == 1 then values[0] else values

         (times) ->
             if times
@@ -220,7 +209,7 @@
         if isType("Function")(name)
             [name, mutator] = ["next", name]

-        @[name] = @createGenerators(generatorConfigs, mutator)
+    toString: -> "[object Stochator]"

     toString: ->
         "[object Stochator]"


Ensure project.serialize is called with atom.saveState options

This is because we have made the `project.serialize(options)` parameter optional
for backwards compatibility (i.e. #11111), and we want to make sure we don't
make the mistake of not passing it internally.

--- spec/atom-environment-spec.coffee
+++ spec/atom-environment-spec.coffee
@@ -202,6 +202,14 @@
       advanceClock atom.saveStateDebounceInterval
       expect(atom.saveState).toHaveBeenCalledWith({isUnloading: true})
       expect(atom.saveState).not.toHaveBeenCalledWith({isUnloading: false})
+
+    it "serializes the project state with all the options supplied in saveState", ->
+      spyOn(atom.project, 'serialize').andReturn({foo: 42})
+
+      waitsForPromise -> atom.saveState({anyOption: 'any option'})
+      runs ->
+        expect(atom.project.serialize.calls.length).toBe(1)
+        expect(atom.project.serialize.mostRecentCall.args[0]).toEqual({anyOption: 'any option'})

   describe "openInitialEmptyEditorIfNecessary", ->
     describe "when there are no paths set", ->


Tests for #82

Tests for #82

--- spec/language-haskell-spec.coffee
+++ spec/language-haskell-spec.coffee
@@ -82,21 +82,6 @@
           ]
         ]

-  it "tokenizes {-  -} comments", ->
-    {tokens} = grammar.tokenizeLine('{--}')
-
-    expect(tokens).toEqual [
-        { value : '{-', scopes : [ 'source.haskell', 'comment.block.haskell', 'punctuation.definition.comment.haskell' ] }
-        { value : '-}', scopes : [ 'source.haskell', 'comment.block.haskell' ] }
-      ]
-
-    {tokens} = grammar.tokenizeLine('{- foo -}')
-    expect(tokens).toEqual  [
-        { value : '{-', scopes : [ 'source.haskell', 'comment.block.haskell', 'punctuation.definition.comment.haskell' ] }
-        { value : ' foo ', scopes : [ 'source.haskell', 'comment.block.haskell' ] }
-        { value : '-}', scopes : [ 'source.haskell', 'comment.block.haskell' ] }
-      ]
-
   describe "ids", ->
     it 'handles type_ids', ->
       typeIds = ['Char', 'Data', 'List', 'Int', 'Integral', 'Float', 'Date']
@@ -314,7 +299,7 @@
     it "=", ->
       data = "x :: String = undefined"
       {tokens} = grammar.tokenizeLine(data)
-      console.log JSON.stringify(tokens, undefined, 2)
+      # console.log JSON.stringify(tokens, undefined, 2)
       expect(tokens).toEqual [
         { value : 'x', scopes : [ 'source.haskell', 'identifier.haskell' ] }
         { value : ' ', scopes : [ 'source.haskell' ] }
@@ -367,3 +352,29 @@
       g.toHaveTokens [['::', ' ', 'a', ' ', '=>=', ' ', 'b']]
       g.toHaveScopes [['source.haskell']]
       g.tokenToHaveScopes [[[4, ['keyword.operator.haskell', 'meta.type-signature.haskell']]]]
+
+  describe "comments", ->
+    it "parses block comments", ->
+      g = grammarExpect grammar, "{- this is a block comment -}"
+      g.toHaveTokens [['{-', ' this is a block comment ', '-}']]
+      g.toHaveScopes [['source.haskell', 'comment.block.haskell']]
+      g.tokenToHaveScopes [[[0, ['punctuation.definition.comment.block.start.haskell']],
+                            [2, ['punctuation.definition.comment.block.end.haskell']]]]
+
+    it "parses nested block comments", ->
+      g = grammarExpect grammar, "{- this is a {- nested -} block comment -}"
+      g.toHaveTokens [['{-', ' this is a ', '{-', ' nested ', '-}', ' block comment ', '-}']]
+      g.toHaveScopes [['source.haskell', 'comment.block.haskell']]
+      g.tokenToHaveScopes [[[0, ['punctuation.definition.comment.block.start.haskell']]
+                            [2, ['punctuation.definition.comment.block.start.haskell']]
+                            [4, ['punctuation.definition.comment.block.end.haskell']]
+                            [6, ['punctuation.definition.comment.block.end.haskell']]]]
+
+    it "parses pragmas as comments in block comments", ->
+      g = grammarExpect grammar, '{- this is a {-# nested #-} block comment -}'
+      g.toHaveTokens [['{-', ' this is a ', '{-', '# nested #', '-}', ' block comment ', '-}']]
+      g.toHaveScopes [['source.haskell', 'comment.block.haskell']]
+      g.tokenToHaveScopes [[[0, ['punctuation.definition.comment.block.start.haskell']]
+                            [2, ['punctuation.definition.comment.block.start.haskell']]
+                            [4, ['punctuation.definition.comment.block.end.haskell']]
+                            [6, ['punctuation.definition.comment.block.end.haskell']]]]


test(draft): new tests for promise chain in send draft

--- spec/tasks/send-draft-spec.coffee
+++ spec/tasks/send-draft-spec.coffee
@@ -313,6 +313,54 @@
           @task.onDependentTaskError(fileUploadTask, new Error("Oh no"))
           expect(@task._notifyUserOfError).toHaveBeenCalled()
           expect(@task._notifyUserOfError.calls.length).toBe 1
+
+        describe "checking the promise chain halts on errors", ->
+          beforeEach ->
+            spyOn(@task,"_makeSendRequest").andCallThrough()
+            spyOn(@task,"_saveNewMessage").andCallThrough()
+            spyOn(@task,"_deleteRemoteDraft").andCallThrough()
+            spyOn(@task,"_notifySuccess").andCallThrough()
+            spyOn(@task,"_onError").andCallThrough()
+
+            @expectBlockedChain = =>
+              expect(@task._makeSendRequest).toHaveBeenCalled()
+              expect(@task._saveNewMessage).not.toHaveBeenCalled()
+              expect(@task._deleteRemoteDraft).not.toHaveBeenCalled()
+              expect(@task._notifySuccess).not.toHaveBeenCalled()
+              expect(@task._onError).toHaveBeenCalled()
+
+          it "halts on 500s", ->
+            thrownError = new APIError(statusCode: 500, body: "err")
+            spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
+              Promise.reject(thrownError)
+            waitsForPromise => @task.performRemote().then (status) =>
+              @expectBlockedChain()
+
+          it "halts on 400s", ->
+            thrownError = new APIError(statusCode: 400, body: "err")
+            spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
+              Promise.reject(thrownError)
+            waitsForPromise => @task.performRemote().then (status) =>
+              @expectBlockedChain()
+
+          it "halts on other errors", ->
+            thrownError = new Error("oh no")
+            spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
+              Promise.reject(thrownError)
+            waitsForPromise => @task.performRemote().then (status) =>
+              @expectBlockedChain()
+
+          it "dosn't halt on success", ->
+            spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
+              options.success?(@response)
+              Promise.resolve(@response)
+            waitsForPromise => @task.performRemote().then (status) =>
+              expect(@task._makeSendRequest).toHaveBeenCalled()
+              expect(@task._saveNewMessage).toHaveBeenCalled()
+              expect(@task._deleteRemoteDraft).toHaveBeenCalled()
+              expect(@task._notifySuccess).toHaveBeenCalled()
+              expect(@task._onError).not.toHaveBeenCalled()
+

     describe "with a new draft", ->
       beforeEach ->


Prefix user name for reply in the shell adapter

--- src/adapters/shell.coffee
+++ src/adapters/shell.coffee
@@ -13,6 +13,7 @@
     @repl.prompt()

   reply: (user, strings...) ->
+    strings = strings.map (s) -> "#{user.name}: #{s}"
     @send user, strings...

   run: ->


Refactored how instructions are encoded; assembler supports all Chip8 instructions

--- src/assembler.coffee
+++ src/assembler.coffee
@@ -28,32 +28,65 @@
     add = (name, expectedParts, encoder) ->
       ret.set name, { expectedParts, encoder }

-    add 'cls', [], ->
-      0x0000
+    add_NNN = (name, code0) ->
+      add name, [LABEL], (parts, labels) ->
+        code0 | (labels.get parts[1])

-    add 'return', [], ->
-      0x000E
+    add_XNN = (name, code0) ->
+      add name, [REGISTER, BYTE], (parts) ->
+        code0 | ((parseInt parts[1][1], 16) << 8) | (parseInt parts[2], 10)

-    add 'jump', [LABEL], (parts, labels) ->
-      0x1000 | (labels.get parts[1])
+    add_XY_ = (name, code0, code3) ->
+      add name, [REGISTER, REGISTER], (parts) ->
+        code1 | ((parseInt parts[1][1], 16) << 8) | ((parseInt parts[2][1], 16) << 4) | code3

-    add 'call', [LABEL], (parts, labels) ->
-      0x2000 | (labels.get parts[1])
+    add_X__ = (name, code0, code23) ->
+      add name, [REGISTER], (parts) ->
+        code0 | ((parseInt parts[1][1], 16) << 8) | code23

-    add 'sei', [REGISTER, BYTE], (parts) ->
-      0x3000 | ((parseInt parts[1][1], 16) << 8) | (parseInt parts[2], 10)

-    add 'snei', [REGISTER, BYTE], (parts) ->
-      0x4000 | ((parseInt parts[1][1], 16) << 8) | (parseInt parts[2], 10)
+    add 'cls', [], -> 0x0000
+    add 'return', [], -> 0x000E

-    add 'ser', [REGISTER, REGISTER], (parts) ->
-      0x5000 | ((parseInt parts[1][1], 16) << 8) | (parseInt parts[2][1], 16)
+    add_NNN 'jump', 0x1000
+    add_NNN 'call', 0x2000
+    add_XNN 'sei', 0x3000
+    add_XNN 'snei', 0x4000
+    add_XY_ 'ser', 0x5000, 0x0000
+    add_XNN 'movi', 0x6000
+    add_XNN 'addi', 0x7000

+    add_XY_ 'movr', 0x8000, 0x0000
+    add_XY_ 'or', 0x8000, 0x0001
+    add_XY_ 'and', 0x8000, 0x0002
+    add_XY_ 'xor', 0x8000, 0x0003
+    add_XY_ 'addr', 0x8000, 0x0004
+    add_XY_ 'subr', 0x8000, 0x0005
+    add_XY_ 'shr', 0x8000, 0x0006
+    add_XY_ 'nsubr', 0x8000, 0x0007
+    add_XY_ 'shl', 0x8000, 0x000E
+    add_XY_ 'sner', 0x9000, 0x0000
+
+    add_NNN 'imovi', 0xA000
+    add_NNN 'jumpoff', 0xB000
+    add_XNN 'rnd', 0xC000
+
+    # _XYN
     add 'sprite', [REGISTER, REGISTER, BYTE], (parts) ->
       0xD000 | ((parseInt parts[1][1], 16) << 8) | ((parseInt parts[2][1], 16) << 4) | (parseInt parts[3])

-    add 'digit', [REGISTER], (parts) ->
-      0xF000 | ((parseInt parts[1][1], 16) << 8) | 0x0033
+    add_X__ 'skr', 0xE000, 0x009E
+    add_X__ 'snkr', 0xE000, 0x00A1
+
+    add_X__ 'rmovt', 0xF000, 0x0007
+    add_X__ 'waitk', 0xF000, 0x000A
+    add_X__ 'movt', 0xF000, 0x0015
+    add_X__ 'movs', 0xF000, 0x0018
+    add_X__ 'iaddr', 0xF000, 0x001E
+    add_X__ 'digit', 0xF000, 0x0029
+    add_X__ 'bcd', 0xF000, 0x0033
+    add_X__ 'store', 0xF000, 0x0055
+    add_X__ 'load', 0xF000, 0x0065

     ret


bug fix [WIP]

bug fix [WIP]

--- src/plugins/server/portalhistory.coffee
+++ src/plugins/server/portalhistory.coffee
@@ -8,7 +8,10 @@
     1. [DESTROY RESONATOR] markup.PLAYER1.team == markup.PORTAL1.team

 毒到对方阵营：
-    1. 两次时间相邻的DESTROY RESONATOR，markup.PORTAL1.team不一致，且中间没有capture   -> 两次之间有毒
+    1. 两次时间相邻的DESTROY RESONATOR，markup.PORTAL1.team不一致，且中间没有capture   -> 最近一次被毒
+    2. 两次中最近一次不符合“毒到自己阵营”                                              -> 最近一次被毒到对方阵营
+
+    1. 最近一次 DESTROY，较远一次 CAPTURE，markup.PORTAL1.team不一致                  -> 最近一次被毒
     2. 两次中最近一次不符合“毒到自己阵营”                                              -> 最近一次被毒到对方阵营

 ###
@@ -70,6 +73,16 @@
                     event:  'capture'
                     portal: item.markup.PORTAL1

+                if lastDestroyEvent?
+                    if lastDestroyEvent.markup.PORTAL1.team isnt item.markup.PORTAL1.team
+                        if lastDestroyEvent.markup.PLAYER1.team isnt lastDestroyEvent.markup.PORTAL1.team
+                            records.push
+                                time:    lastDestroyEvent.time
+                                player:  lastDestroyEvent.markup.PLAYER1
+                                event:   'flip'
+                                event2:  if lastDestroyEvent.markup.PLAYER1.team is 'ENLIGHTENED' then 'ADA Refactor' else 'Jarvis Virus'
+                                portal:  lastDestroyEvent.markup.PORTAL1
+
                 lastCaptureEvent = item
                 return next()


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -1,5 +1,5 @@
 ###*
-The Clampable module provides helper methods to tween object properties.
+The Clampable module provides helper methods to clamp object properties.

 @name Clampable
 @module


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -9,4 +9,5 @@
   clamp: (data) ->
     Object.extend(I.clampData, data)

-  clampToBounds: ()->+  clampToBounds: (bounds) ->
+    bou


base-domainify: addClass(Class)

base-domainify: addClass(Class)

--- src/base-domainify.coffee
+++ src/base-domainify.coffee
@@ -84,7 +84,7 @@
             path = @relativePath + '/' + name

             coffeeCode += """
-                #{_}@addClass '#{name}', require('#{path}')\n
+                #{_}@addClass require('#{path}')\n
             """

         coffeeCode += "#{_}return\n"


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/collision.coffee
+++ src/collision.coffee
@@ -216,7 +216,7 @@
     ###
     rayRectangle: (source, direction, target) ->
       unless target.xw? and target.yw?
-        return Collision.rayRectangle(sou)
+        return Collision.rayRectangle(source, direction, )

       xw = target.xw
       yw = target.yw


correct handle file replacement in list

correct handle file replacement in list

--- app/assets/javascripts/uploadcare/widget/tabs/preview-tab-multiple.js.coffee
+++ app/assets/javascripts/uploadcare/widget/tabs/preview-tab-multiple.js.coffee
@@ -37,13 +37,11 @@

       @dialogApi.fileColl.onAdd.add(@__fileAdded, @__updateContainerView)
       @dialogApi.fileColl.onRemove.add(@__fileRemoved, @__updateContainerView)
+      @dialogApi.fileColl.onReplace.add(@__fileReplaced, @__updateContainerView)

       @dialogApi.fileColl.onAnyDone.add(@__fileDone)
       @dialogApi.fileColl.onAnyFail.add(@__fileFailed)
       @dialogApi.fileColl.onAnyProgress.add(@__fileProgress)
-
-      @dialogApi.fileColl.onReplace.add (oldFile, newFile) =>
-        $(newFile).data('dpm-el', @__fileToEl(oldFile))

       @__setupSorting()

@@ -139,17 +137,27 @@
       @__find('file-error', fileEl)
         .text(t("errors.#{error}"))

-    __fileAdded: (file) =>
-      $(file).data('dpm-el', @__createFileEl(file))
+    __fileAdded: (file, afterFile) =>
+      fileEl = @__createFileEl(file)
+      if afterFile?
+        afterFileEl = @__fileToEl(afterFile)
+        fileEl.insertAfter(afterFileEl)
+      else
+        fileEl.appendTo(@fileListEl)
+      $(file).data('dpm-el', fileEl)

     __fileRemoved: (file) =>
       @__fileToEl(file).remove()
+      $(file).removeData()
+
+    __fileReplaced: (oldFile, newFile) =>
+      @__fileAdded(newFile, oldFile)
+      @__fileRemoved(oldFile)

     __fileToEl: (file) ->
       $(file).data('dpm-el')

     __createFileEl: (file) ->
       @__fileTpl.clone()
-        .appendTo(@fileListEl)
         .on 'click', '.' + CLASS_PREFIX + 'file-remove', =>
           @dialogApi.fileColl.remove(file)


Tooltips: added permanent option

Tooltips: added permanent option

--- src/core/view.coffee
+++ src/core/view.coffee
@@ -881,6 +881,7 @@
     o.fallback  or= o.title
     o.view      or= null
     o.sticky     ?= no
+    o.permanent  ?= no
     o.delegate  or= this
     o.events    or= ['mouseenter','mouseleave','mousemove']


ログインが表示されない不具合修正

ログインが表示されない不具合修正

--- app/assets/javascripts/components/navbar/user.js.cjsx
+++ app/assets/javascripts/components/navbar/user.js.cjsx
@@ -14,7 +14,7 @@
       </li>

   render: ->
-    return null if @props.current_user.unmount?
+    return null if @props.current_user? and @props.current_user.unmount?
     <ul className='uk-navbar-nav edit-user'>
       {@userDom()}
     </ul>


Shim Array::indexOf in the keyboard manager

--- app/assets/javascripts/exo/keyboard_manager.js.coffee
+++ app/assets/javascripts/exo/keyboard_manager.js.coffee
@@ -1,4 +1,8 @@
 namespace 'Exo', (exports) ->
+  Array::indexOf ||= (item) ->
+    return i for x, i in this when x is item
+    -1
+
   class exports.KeyboardManager

     _map = {


change texts on preview tab

change texts on preview tab

--- app/assets/javascripts/uploadcare/locale/en.js.coffee
+++ app/assets/javascripts/uploadcare/locale/en.js.coffee
@@ -42,9 +42,9 @@
             button: 'Upload'
           preview:
             unknownName: 'unknown'
-            change: 'Change file'
+            change: 'Cancel'
             back: 'Back'
-            done: 'Select'
+            done: 'Upload'
             unknown:
               title: 'Uploading. Please wait for a preview.'
               done: 'Skip preview and accept'
@@ -54,7 +54,7 @@
               line2: 'Please confirm.'
             image:
               title: 'Upload this image?'
-              change: 'Change image'
+              change: 'Cancel'
             error:
               default:
                 title: 'Uploading failed'


fix availability info display

fix availability info display

--- resources/assets/coffee/react/beatmapset-page/header.coffee
+++ resources/assets/coffee/react/beatmapset-page/header.coffee
@@ -152,14 +152,15 @@
               className: 'beatmapset-header__availability-info',
               if @props.beatmapset.availability.download_disabled
                 osu.trans 'beatmapsets.availability.disabled'
-              else if @props.beatmapset.availability.more_information?
-                el React.Fragment, null,
-                  osu.trans 'beatmapsets.availability.parts-removed'
-                  div className: 'beatmapset-header__availability-link',
-                    a
-                      href: @props.beatmapset.availability.more_information
-                      target: '_blank'
-                      osu.trans 'beatmapsets.availability.more-info'
+              else
+                osu.trans 'beatmapsets.availability.parts-removed'
+
+              if @props.beatmapset.availability.more_information?
+                div className: 'beatmapset-header__availability-link',
+                  a
+                    href: @props.beatmapset.availability.more_information
+                    target: '_blank'
+                    osu.trans 'beatmapsets.availability.more-info'

           div
             className: 'beatmapset-header__buttons'


KodingListController: Emit "ItemLoaded" event when first loadItems call

--- client/app/lib/kodinglist/kodinglistcontroller.coffee
+++ client/app/lib/kodinglist/kodinglistcontroller.coffee
@@ -114,6 +114,7 @@
     @showLazyLoader no

     @fetch @filterStates.query, (items) =>
+      @emit 'ItemsLoaded', items
       return @showNoItemWidget()  unless items?.length

       @addListItems items


remove another reference to avatar header

The "avatar header" was apparently the text which used to show the group title.

--- client/landing/app/MainApp/sidebar/sidebarview.coffee
+++ client/landing/app/MainApp/sidebar/sidebarview.coffee
@@ -205,7 +205,6 @@

     @$('.avatar-placeholder').removeClass "collapsed"
     @$('#finder-panel').removeClass "expanded"
-    @avatarHeader.show() unless @avatarHeader.getData().slug is 'koding'
     if parseInt(@contentPanel.$().css("left"), 10) < 174
       @contentPanel.setClass "mouse-on-nav"
     @utils.wait 300, => callback?()


Get oldValue.constructor if it's a delete mutation.

--- source/hamsa.coffee
+++ source/hamsa.coffee
@@ -81,13 +81,15 @@
     ###
     @observe: (callback, @events = DEFAULT_EVENTS) ->
       observer = Object.observe @records, (states) =>
-        for state in states when @records[state.name].constructor is @
-          event = type: state.type, name: state.name
-          if state.type in ["add", "update"]
-            event.object = @records[state.name]
-          else
-            event.oldValue = state.oldValue
-          callback event
+        for state in states
+          constructor = @records[state.name]?.constructor or state.oldValue.constructor
+          if constructor is @
+            event = type: state.type, name: state.name
+            if state.type in ["add", "update"]
+              event.object = @records[state.name]
+            else
+              event.oldValue = state.oldValue
+            callback event
       , @events
       @callbacks.push callback
       @observers.push observer


branches is a splat

branches is a splat

--- source/latte.coffee
+++ source/latte.coffee
@@ -2,7 +2,7 @@
 #   obj({a:1}) fun(supafn) obj({bla: 2}) -> code_1
 #   type(String) -> code_2

-match = (self, branches) ->
+match = (self, branches...) ->
   ->
     args = Array.prototype.slice.call(arguments, 0)
     args = args.sort()


Add comments

Add comments

--- common/lib/xmodule/xmodule/js/src/capa/display.coffee
+++ common/lib/xmodule/xmodule/js/src/capa/display.coffee
@@ -310,6 +310,9 @@
       'R3'  --> 'R_{3}'
       'vGS' --> 'v_{GS}'
       'K/2*(vIN-VT)^2' --> 'K/2*(v_{IN}-V_{T})^2'
+
+    ... and also escape specific 6.002x-related keywords from MathJax,
+        such as 'in' (parsed by MathJax as the set symbol)
     ###

     # Default keywords are taken from capa/calc.py
@@ -318,7 +321,7 @@
     # Escape keywords are strings that have special meaning in 6.002x that should not be processed by Jax
     escape_keywords = ['in']

-    # First, perform subscript insertion
+    # First, perform subscript insertion, but watch out for keywords
     replace_subscript = (match) ->
       if match in default_keywords or match in escape_keywords
         return match


retain anchors

retain anchors

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -90,8 +90,8 @@
     window.history.pushState { turbolinks: true, position: currentState.position + 1 }, '', url

 reflectRedirectedUrl = (xhr) ->
-  if (location = xhr.getResponseHeader('X-XHR-Current-Location'))
-    window.history.replaceState currentState, '', location
+  unless (location = xhr.getResponseHeader 'X-XHR-Current-Location') is document.location.pathname + document.location.search
+    window.history.replaceState currentState, '', location + document.location.hash

 rememberCurrentUrl = ->
   window.history.replaceState { turbolinks: true, position: Date.now() }, '', document.location.href


Include the hash fix as part of the resetScrollPosition implementation, as that is where it belongs, and how we can restore onload to being at the same level of abstraction

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -27,10 +27,7 @@
       reflectNewUrl url
       changePage extractTitleAndBody(doc)...
       reflectRedirectedUrl()
-      if document.location.hash
-        document.location.href = document.location.href
-      else
-        resetScrollPosition()
+      resetScrollPosition()
       triggerEvent 'page:load'
     else
       document.location.href = url
@@ -113,7 +110,10 @@
   window.scrollTo page.positionX, page.positionY

 resetScrollPosition = ->
-  window.scrollTo 0, 0
+  if document.location.hash
+    document.location.href = document.location.href
+  else
+    window.scrollTo 0, 0

 removeHash = (url) ->
   link = url


Draw-arc

Draw-arc

--- src/draw_grid.coffee
+++ src/draw_grid.coffee
@@ -37,11 +37,17 @@
         stroke: "#88ff88"
       }
     ]
+  draw_arc = (width, x_sign, y_sign) ->
+    "a#{width},#{width} 0 0,1 #{x_sign*width},#{y_sign*width} "
+
   draw_turtle_path = (i, j) ->
+    width = cell_size / 2
     x = i*cell_size
     y = j*cell_size
-    path = "M#{x},#{y} H100 V100"
-    S.path {class: "path-turtle", d: path , stroke: "#00ff00"}
+    path = "M#{x},#{y} "
+    path += draw_arc(width,  1, 1)
+    path += draw_arc(width, -1,-1)
+    S.path {class: "path-turtle", d: path, stroke: "#00ff00", fill: "#88ff88"}

   grid_path = ""
   for n in [0..grid_size] by cell_size


handle builder as well

handle builder as well

--- src/dt-stream.coffee
+++ src/dt-stream.coffee
@@ -85,6 +85,7 @@
         el._stream = new Entry el, parent
         @opened_tags++
         el._stream.write =>
+            return if el is el.builder
             if el.closed is 'self'
                 @write prettify el, "<#{el.name}#{attrStr el.attrs}/>"
             else
@@ -98,7 +99,7 @@

     onclose: (el) ->
         el._stream.write =>
-            unless el.closed is 'self'
+            unless el.closed is 'self' or el is el.builder
                 @write prettify el, "</#{el.name}>"
             # call next callback of the registered 'ready' checker
             el._stream_ready?()


Removed unused variable

Removed unused variable

--- js-library/app/js/loader.coffee
+++ js-library/app/js/loader.coffee
@@ -4,7 +4,6 @@

 iframe = document.createElement('iframe')
 div = document.createElement('div')
-hasReadyState = 'readyState' of iframe
 flScript = document.createElement('script')

 iframeLoaded = false


Fix attribute mapping.

Fix attribute mapping.

--- src/coffee/mapping.coffee
+++ src/coffee/mapping.coffee
@@ -185,10 +185,10 @@

   _attributes: (xml, elem) ->
     val = elem.value
-    if _.has(val, 'key') and _.has(val, 'value')
+    if _.has(val, 'key') and _.has(val, 'label')
       val = val.key
     if _.has(val, 'centAmount') and _.has(val, 'currencyCode')
-      val = "#{currencyCode} #{centAmount}"
+      val = "#{val.currencyCode} #{val.centAmount}"
     xml.e('name').t(elem.name).up()
       .e('value').t(val)


- build

- build

--- lib/crystal/generate.coffee
+++ lib/crystal/generate.coffee
@@ -197,10 +197,8 @@
 				for property_name of schema.properties
 					property = schema.properties[property_name]
 					if property.config && validate_spec[property_name] == undefined
-						if property.config == true
+						if property.config == true and this.config[property_name]
 							validate_spec[property_name] = this.config[property_name]
-						else
-							validate_spec[property_name] = handlebars.compile(property.config) this.config

 				validate_spec = sortObject(validate_spec)


Removed parentheses from the level status view

--- lib/level-status-view.coffee
+++ lib/level-status-view.coffee
@@ -53,7 +53,7 @@
     # TODO check is level name is to long, shorten the link?
     activeLevelName = @activeLevel.getName()
     # ------------------------------------------------------
-    @levelStatusLink.text("(#{activeLevelName})")
+    @levelStatusLink.text("#{activeLevelName}")
     @levelStatusLink.attr('data-level',activeLevelName)

   ## Showing and hiding this view ----------------------------------------------


test(service): fix command exit code in startup

--- packages/service/test/index.config.startup.coffee
+++ packages/service/test/index.config.startup.coffee
@@ -66,7 +66,8 @@
       nikita
         ssh: ssh
       , ->
-        {status} = await @execute 'command -v chkconfig', code_skipped: 1
+        # Note, `-v` flag differ between bash (exit code 1) and sh (exit code 127)
+        {status} = await @execute 'command -v chkconfig', code_skipped: 127, metadata: relax: true
         return unless status
         @service.remove
           name: service.name


fix(app): use new ng-classify app syntax

--- generators/app/templates/src/app/app.coffee
+++ generators/app/templates/src/app/app.coffee
@@ -1,9 +1,10 @@
 class App extends App
-	@constructor = [
-		'ngRoute'
-		# coffeelint: disable=coffeescript_error
-		<% if (useBackendless) { %>
-		'ngMockE2E'
-		<% } %>
-		# coffeelint: enable=coffeescript_error
-	]+	constructor: ->
+		return [
+			'ngRoute'
+			# coffeelint: disable=coffeescript_error
+			<% if (useBackendless) { %>
+			'ngMockE2E'
+			<% } %>
+			# coffeelint: enable=coffeescript_error
+		]


Fix wrong color eraser on background change

In dotstorm, changing the background was leading to weird results.
Fixes half of issue #27.

--- plugins/dotstorm/assets/dotstorm/js/editor.coffee
+++ plugins/dotstorm/assets/dotstorm/js/editor.coffee
@@ -34,6 +34,7 @@
     setTimeout (=> @delegateEvents()), 100

   redraw: =>
+    @lastTool = null
     for action in @actions
       @drawAction(action)

@@ -363,6 +364,7 @@

   handleChangeBackgroundColor: (event) =>
     @changeBackgroundColor $(event.currentTarget).css("background-color")
+    @canvas.redraw()
     return false

   changeBackgroundColor: (color) =>


Remove unused code

Remove unused code

--- src/config/sprites.coffee
+++ src/config/sprites.coffee
@@ -8,8 +8,6 @@
     _EXPORTS = ["step", "reset"]
     world.authority = args
     world.add_child "sprite #{args.label()}"
-  stroke: "black"
-  path: "M0,0 L50,50 H50 V50 Z"
   angle: (world, args) ->
     # TODO: perform real triginometry
     v_i = world.get('v_i')


Fix proper pane redistribution when coming from strange pane configurations

--- lib/n-panes-functions.coffee
+++ lib/n-panes-functions.coffee
@@ -16,11 +16,9 @@

 mergeUntilNPanes = (n, horizontal) ->
   panes = getOrientationPanes(horizontal)
-  paneCount = panes.length
-  while paneCount > n
+  while panes.length > n
     mergeTwoPanes(panes[-1..][0], panes[-2..][0])
     panes = getOrientationPanes(horizontal)
-    paneCount = panes.length

 mergeTwoPanes = (lastPane, secondToLastPane) ->
   lastPaneItems = lastPane.getItems()
@@ -31,9 +29,20 @@
 module.exports =
   ensurePanes: (n, horizontal) ->
     revPaneCount = getOrientationPanes(!horizontal).length
-    if revPaneCount > 1
+    paneCount = getOrientationPanes(horizontal).length
+    # If true, there is a number of horizontal panes within vertical panes or vice versa
+    forceToOneA = (revPaneCount > 0 and paneCount > 1) or (revPaneCount > 1 and paneCount > 0)
+    # If true, possible transition from grid to horizontal panes
+    forceToOneB = (!horizontal) and paneCount >= 4 and paneCount % 2 == 0
+    if forceToOneA or forceToOneB
+      # We can't properly identify the panes, we'll merge all until only one pane is left
+      panes = atom.workspace.getPanes()
+      paneCount = 1
+      while panes.length > 1
+        mergeTwoPanes(panes[-1..][0], panes[-2..][0])
+        panes = atom.workspace.getPanes()
+    else if revPaneCount > 1
       mergeUntilNPanes(1, !horizontal)
-    paneCount = getOrientationPanes(horizontal).length
     if paneCount < n
       addUntilNPanes(n, horizontal)
     else if paneCount > n


Fixed typo

Fixed typo

--- core/app/backbone/views/facts/react_discussion.coffee
+++ core/app/backbone/views/facts/react_discussion.coffee
@@ -22,7 +22,7 @@
     step: 0

   componentDidMount: ->
-    window.curentUser?.on 'change', @onChange, @
+    window.currentUser?.on 'change', @onChange, @

   componentWillUnmount: ->
     window.currentUser?.off null, null, @


:lipstick:

:lipstick:

--- lib/project-find-view.coffee
+++ lib/project-find-view.coffee
@@ -90,7 +90,7 @@

     @subscribe @model, 'cleared', => @clearMessages()
     @subscribe @model, 'replacement-state-cleared', (results) => @generateResultsMessage(results)
-    @subscribe @model, 'finished-searching', (result) => @onFinishedSearching(result)
+    @subscribe @model, 'finished-searching', (results) => @generateResultsMessage(results)
     @findEditor.getBuffer().on 'changed', => @model.clear()
     @replaceEditor.getBuffer().on 'changed', => @model.clearReplacementState()

@@ -204,9 +204,6 @@
   onFinishedReplacing: (results) ->
     atom.beep() unless results.replacedPathCount
     @replacmentInfoBlock.hide()
-
-  onFinishedSearching: (results) ->
-    @generateResultsMessage(results)

   generateResultsMessage: (results) =>
     message = Util.getSearchResultsMessage(results)


Re-enable terminal splits.

Re-enable terminal splits.

--- lib/rubinius-terminal.coffee
+++ lib/rubinius-terminal.coffee
@@ -88,11 +88,9 @@
     @subscriptions = new CompositeDisposable

     @subscriptions.add atom.commands.add 'atom-workspace', 'rubinius-terminal:open': => @newTerminal()
-    ###
     ['left', 'right', 'top', 'bottom'].forEach (direction) =>
       @subscriptions.add atom.commands.add 'atom-workspace', "rubinius-terminal:split-#{direction}", @splitTerminal(direction)
     @subscriptions.add atom.commands.add 'atom-workspace', 'rubinius-terminal:pipe-path': => @pipeTerminal
-    ###

     ###
     TODO: update to current CommandRegistry


Fix GCM result parsing

Fix GCM result parsing

--- lib/pushservices/gcm.coffee
+++ lib/pushservices/gcm.coffee
@@ -50,7 +50,7 @@
                 @handleResult multicastResult, message.subscribers[0]

     handleResult: (result, subscriber) ->
-        if result.messageId
+        if result.messageId or result.message_id
             # if result.canonicalRegistrationId
                 # TODO: update subscriber token
         else


Temporarily disable this test, needs thinking

--- spec/Scoping.coffee
+++ spec/Scoping.coffee
@@ -281,6 +281,7 @@
       in1.endGroup()
       in1.disconnect()
     it 'should forward new-style brackets as expected regardless of sending order', (done) ->
+      return @skip 'Temporarily skipped, needs some thinking'
       expected = [
         'CONN'
         '< 1'


Clean up generator runner

Clean up generator runner

--- src/core/generator.coffee
+++ src/core/generator.coffee
@@ -5,45 +5,39 @@

 runGenerator = (env, contents, generator, callback) ->

-  run = (callback) ->
-    # run the generator
-    generator.fn contents, callback
-
-  merge = (generated, callback) ->
+  merge = (items, root, callback) ->
     # merge output of generator back into content tree
-    m = (items, root, callback) ->
-      async.forEach Object.keys(items), (key, callback) ->
-        if items[key] instanceof ContentPlugin
-          if root[key]?
-            env.logger.warning "generator output overwrites previous item for '#{ key }'"
-          env.logger.verbose "generator merging '#{ key }'"
-          root[key] = items[key]
-          root._[generator.group].push items[key]
-          items[key].parent = root
-          items[key].__filename = 'generator'
-          callback()
-        else if items[key] instanceof Object
-          if contents[key]?
-            if contents[key] instanceof ContentTree
-              m items[key], contents[key], callback
-            else
-              env.logger.warning "generator tries to overwrite existing item '#{ key }'' with directory, ignoring output."
-              callback()
+    async.forEach Object.keys(items), (key, callback) ->
+      if items[key] instanceof ContentPlugin
+        env.logger.verbose "generator merging '#{ key }'"
+        if root[key]?
+          env.logger.warning "generator output overwrites previous item for '#{ key }'"
+        root[key] = items[key]
+        root._[generator.group].push items[key]
+        items[key].parent = root
+        items[key].__filename = 'generator'
+        callback()
+      else if items[key] instanceof Object
+        if root[key]?
+          if root[key] instanceof ContentTree
+            merge items[key], root[key], callback
           else
-            env.logger.verbose "generator creating subtree '#{ key }'"
-            tree = new ContentTree env, key
-            tree.parent = root
-            tree.parent._.directories.push tree
-            root[key] = tree
-            m items[key], tree, callback
+            env.logger.warning "generator tries to overwrite existing item '#{ key }' with a tree, ignoring output."
+            callback()
         else
-          callback new Error "invalid generator output for '#{ key }'"
-      , callback
-    m generated, contents, (error) -> callback error, contents
+          env.logger.verbose "generator creating subtree '#{ key }'"
+          tree = new ContentTree env, key
+          tree.parent = root
+          tree.parent._.directories.push tree
+          root[key] = tree
+          merge items[key], tree, callback
+      else
+        callback new Error "invalid generator output for '#{ key }'"
+    , (error) -> callback error, root

   async.waterfall [
-    run
-    merge
+    (callback) -> generator.fn contents, callback
+    (generated, callback) -> merge generated, contents, callback
   ], callback

 ### Exports ###


Remove weird export for circular usage

Remove weird export for circular usage

--- src/flux/task.coffee
+++ src/flux/task.coffee
@@ -3,12 +3,8 @@
 moment = require 'moment'
 flux = require 'flux-react'

-{TimeStore} = require './time'
+Durations = require '../helpers/durations'
 {CrudConfig, makeSimpleStore, extendConfig} = require './helpers'
-# export the module immediatly before requiring task-step
-# Unfortunantly task-step also needs access to the TaskStore so we export the definition before we require it.
-# The exported object is extended below after the definition
-module.exports = {}
 {TaskStepStore} = require './task-step'

 getSteps = (steps) ->
@@ -195,8 +191,7 @@
       allSteps.length

     isTaskPastDue: (taskId) ->
-      task = @_get(taskId)
-      moment(TimeStore.getNow()).isAfter(task.due_at)
+      Durations.isPastDue( @_get(taskId) )

     isPractice: (taskId) ->
       practices = [
@@ -228,5 +223,4 @@

 extendConfig(TaskConfig, new CrudConfig())
 {actions, store} = makeSimpleStore(TaskConfig)
-# Extend the exports with the actual implementation.  The actual export took place at the top of the file
-_.extend(module.exports, {TaskActions:actions, TaskStore:store})
+module.exports = {TaskActions:actions, TaskStore:store}


Fix: declare list indices before using them

--- lib/text-manipulation.coffee
+++ lib/text-manipulation.coffee
@@ -37,13 +37,13 @@
     if not containingList?
       null
     else
+      {listRange: [listStartIx,listEndIx], nonNestedRanges: nonNestedIxRanges} = containingList
       listElements =
         if (bufferText.slice listStartIx, listEndIx).match(/^\s*$/)
           # Because empty elements are allowed, "[\s*]" will be interpreted as a list with single empty element
           # TODO: For now, disallow this, as it requires some changes to the model to accomodate the whitespace in an empty list
           []
         else
-          { listRange: [listStartIx,listEndIx], nonNestedRanges: nonNestedIxRanges} = containingList
           #nonNestedIxRanges = leftIxRanges.concat rightIxRanges
           elementRanges = @getElementRangesFromNonNested bufferText, listStartIx, listEndIx, nonNestedIxRanges
           # @showIxRanges bufferText, elementRanges


Let getElementRangesFromNonNested allow empty list elements

--- lib/text-manipulation.coffee
+++ lib/text-manipulation.coffee
@@ -144,11 +144,11 @@
           separator = bufferText[ix]

         if (separator? && bufferText[ix] == separator)
-          elementRanges.push [elementStart, ix] if elementStart != ix # TODO: empty check prob. not necessary
+          elementRanges.push [elementStart, ix]
           elementStart = ix+1
         ix++

-    elementRanges.push [elementStart, endIx] if elementStart != endIx
+    elementRanges.push [elementStart, endIx]
     # console.log elementRanges
     elementRanges


:calendar:

:calendar:

--- scripts/ayp.coffee
+++ scripts/ayp.coffee
@@ -91,8 +91,8 @@
     # Bouncers are hard or something, whatever.
     name = 'arbo'

-  if name == 'sflios' || name == 'PITlios'
-    # He visited this one time. And then moved that other time.
+  if name == 'sflios' || name == 'PITlios' || name == 'missourios77'
+    # He visited this one time. And then moved that other time. And then did a joke.
     # http://pixxx.wtf.cat/image/0Q3B34330v0c/12188116_10205398142892807_4244989619067012464_o.jpg
     name = 'solios'


Proxy environment Real IP directive options

Signed-off-by: Sonmez Kartal <d2d15c3d37396a5f2a09f8b42cf5f27d43a3fbde@koding.com>

--- deployment/nginx.coffee
+++ deployment/nginx.coffee
@@ -247,6 +247,13 @@
     mime_types = "include #{path};"
     break

+  if isProxy KONFIG.ebEnvName
+    KONFIG.nginx =
+      real_ip:
+        from: '10.0.0.0/16'
+        header: 'proxy_protocol'
+        recursive: 'off'
+
   config = """
   worker_processes #{if inDevEnvironment then 1 else 16};
   master_process #{if inDevEnvironment then 'off' else 'on'};
@@ -439,13 +446,10 @@
    '''

 createListenDirective = (KONFIG, env) ->
-  return "listen #{KONFIG.publicPort};" if not isProxy KONFIG.ebEnvName
-
-  return '''
-    listen 79 proxy_protocol;
-    real_ip_header proxy_protocol;
-    set_real_ip_from 10.0.0.0/16;
-  '''
+  if isProxy KONFIG.ebEnvName
+    return 'listen 79 proxy_protocol;'
+  else
+    return "listen #{KONFIG.publicPort};"

 createHttpsRedirector = (KONFIG) ->
   return '' if isProxy KONFIG.ebEnvName


fix body checking

fix body checking

--- device/test/main.coffee
+++ device/test/main.coffee
@@ -10,7 +10,7 @@

 global.opts = (obj = {}) ->
   obj['content-type'] = 'application/x-www-form-urlencoded'
-  if body of obj
+  if 'body' of obj
     obj.body = qs.stringify obj.body
   obj
 global.ok = (res) ->


Only get the device id once, rather than for every request to `updateDeviceInfo`

--- src/application.coffee
+++ src/application.coffee
@@ -277,32 +277,44 @@
 		# Set the updating as finished
 		currentlyUpdating = 0

+getDeviceID = do ->
+	deviceIdPromise = null
+	return ->
+		# We initialise the rejected promise just before we catch in order to avoid a useless first unhandled error warning.
+		deviceIdPromise ?= Promise.rejected()
+		# Only fetch the device id once (when successful, otherwise retry for each request)
+		deviceIdPromise = deviceIdPromise.catch ->
+			Promise.all([
+				knex('config').select('value').where(key: 'apiKey')
+				knex('config').select('value').where(key: 'uuid')
+			])
+			.spread ([{value: apiKey}], [{value: uuid}]) ->
+				resinAPI.get(
+					resource: 'device'
+					options:
+						select: 'id'
+						filter:
+							uuid: uuid
+					customOptions:
+						apikey: apiKey
+				)
+			.then (devices) ->
+				if devices.length is 0
+					throw new Error('Could not find this device?!')
+				return devices[0].id
+
 exports.updateDeviceInfo = updateDeviceInfo = (body) ->
 	Promise.all([
 		knex('config').select('value').where(key: 'apiKey')
-		knex('config').select('value').where(key: 'uuid')
-	])
-	.spread ([{value: apiKey}], [{value: uuid}]) ->
-		resinAPI.get(
+		getDeviceID()
+	]).spread ([{value: apiKey}], deviceID) ->
+		resinAPI.patch(
 			resource: 'device'
-			options:
-				select: 'id'
-				filter:
-					uuid: uuid
+			id: deviceID
+			body: body
 			customOptions:
 				apikey: apiKey
 		)
-		.then (devices) ->
-			if devices.length is 0
-				throw new Error('Could not find this device?!')
-			deviceID = devices[0].id
-			resinAPI.patch(
-				resource: 'device'
-				id: deviceID
-				body: body
-				customOptions:
-					apikey: apiKey
-			)
 	.catch (error) ->
 		utils.mixpanelTrack('Device info update failure', {error, body})


In largeFileMode, base maxLineLength on the longest line we’ve seen

This is pretty hacky. If we want to compute the true longest line, we’ll
need to process every line, which is what large file mode is designed
to avoid. So now whenever the display buffer returns a line, it has
the potential to update the longest line.

This is a bit weird because retrieving a line now has a side effect.
It’s even more weird because the longest line will actually be wrong for
the initial state updates in the TextEditorPresenter. But as soon as
the user interacts in any way the dimensions are recomputed, so it works
for now.

A better approach may be to set a visible region on the display buffer.
But I’d like to keep this low-touch until we have a chance to revisit
the design of DisplayBuffer in a bigger way.

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -479,7 +479,11 @@
   # Returns {TokenizedLine}
   tokenizedLineForScreenRow: (screenRow) ->
     if @largeFileMode
-      @tokenizedBuffer.tokenizedLineForRow(screenRow)
+      line = @tokenizedBuffer.tokenizedLineForRow(screenRow)
+      if line.text.length > @maxLineLength
+        @maxLineLength = line.text.length
+        @longestScreenRow = screenRow
+      line
     else
       @screenLines[screenRow]

@@ -760,19 +764,13 @@
   #
   # Returns a {Number}.
   getMaxLineLength: ->
-    if @largeFileMode
-      100
-    else
-      @maxLineLength
+    @maxLineLength

   # Gets the row number of the longest screen line.
   #
   # Return a {}
   getLongestScreenRow: ->
-    if @largeFileMode
-      0
-    else
-      @longestScreenRow
+    @longestScreenRow

   # Given a buffer position, this converts it into a screen position.
   #


Keyboard nav StatusListView

Keyboard nav StatusListView

--- lib/status-list-view.coffee
+++ lib/status-list-view.coffee
@@ -17,6 +17,8 @@

 """
+
+FileSummaryTag = "git-experiment-file-summary-view"

 class StatusListView extends HTMLElement
   initialize: (@repositoryView) ->
@@ -45,7 +47,7 @@
     @handleEvents()

   handleEvents: =>
-    @el.on "click", "git-experiment-file-summary-view", @entryClicked.bind(@)
+    @el.on "click", FileSummaryTag, @entryClicked.bind(@)
     atom.commands.add "git-experiment-status-list-view",
       'core:move-down': @moveSelectionDown
       'core:move-up': @moveSelectionUp
@@ -70,11 +72,11 @@
       @commitMessageView.update()
       @undoCommitView.update()
       @setIndices()
-      @selectStatus()
+      @selectDefaultStatus()
+      @focus()

   setIndices: ->
-    entries = @querySelectorAll("git-experiment-file-summary-view")
-    for entry, idx in entries
+    for entry, idx in @getAllEntries()
       entry.index = idx

   isUnstaged: (status) ->
@@ -97,6 +99,17 @@
            bit & codes.INDEX_RENAMED ||
            bit & codes.INDEX_TYPECHANGE

+  selectDefaultStatus: ->
+    entries = @getAllEntries()
+    for entry in entries
+      if entry.path == @selectedPath and entry.status == @selectedStatus
+        entry.click()
+        return
+    if entry = entries[@selectedIndex] || entries[@selectedIndex-1]
+      entry.click()
+      return
+    entries[0]?.click()
+
   selectedEntry: ->
     @querySelector(".selected")

@@ -111,6 +124,9 @@
     @deselect(selectedEntries)
     entry.classList.add("selected")
     entry
+
+  getAllEntries: ->
+    @querySelectorAll(FileSummaryTag)

   getSelectedEntries: ->
     @querySelectorAll(".selected")
@@ -129,8 +145,20 @@
     @commitMessageView.focusTextArea()

   moveSelectionUp: =>
+    selected = @selectedEntry()
+    prev = selected.previousElementSibling
+    unless prev
+      if selected.status == 'staged'
+        prev = @querySelector(".unstaged #{FileSummaryTag}:last-of-type")
+    prev?.click()

   moveSelectionDown: =>
+    selected = @selectedEntry()
+    next = selected.nextElementSibling
+    unless next
+      if selected.status == 'unstaged'
+        next = @querySelector(".staged #{FileSummaryTag}")
+    next?.click()

 module.exports = document.registerElement "git-experiment-status-list-view",
   prototype: StatusListView.prototype


Consequence for Setting Properties Directly


Fix disqus do not work well

Fix disqus do not work well


updated script

updated script

--- src/instagram.coffee
+++ src/instagram.coffee
@@ -28,7 +28,7 @@
       text = msg.match[3].trim()
       text = text.split(" ")
       tag =  text[0]
-      count = text[1] if text[1]
+      count = parseInt(text[1]) if text[1]
     else
       msg.send 'Please provied tag'
       return


removed unused variable

removed unused variable

--- BackofficeBundle/Resources/public/coffee/page/NodeView.coffee
+++ BackofficeBundle/Resources/public/coffee/page/NodeView.coffee
@@ -31,7 +31,6 @@
     return

   render: ->
-    viewContext = @
     parameters = appRouter.extractParameters()
     if parameters.length > 0  and parameters[0] == @options.node.attributes.node_id
       @setElement @renderTemplate('OpenOrchestraBackofficeBundle:BackOffice:Underscore/nodeView',