[#4] Adiciona percentual do autorizado e ordena

--- app/assets/javascripts/angular_app/directives/uoGraph.js.coffee
+++ app/assets/javascripts/angular_app/directives/uoGraph.js.coffee
@@ -1,20 +1,25 @@
 angular.module('InescApp').directive 'uoGraph', ['$filter', ($filter) ->
   columns = [
-    { sTitle: 'Entidade Orçamentária', bSortable: false },
+    { sTitle: 'Entidade Orçamentária', bSortable: false }
     { sTitle: 'Orçamento Autorizado', bSortable: false }
+    { sTitle: '%', bSortable: false }
+    { sTitle: 'Orçamento Autorizado', bVisible: false } # Usado só para sorting
   ]

-  processData = (data, year) ->
-    data.map (uo) ->
-      entityUrl = $filter('entityUrl')
-      currency = $filter('currency')
-      console.log(uo)
-      ["#{uo.label}",
-        currency(uo.amount, '')]
+  processData = (entity, year) ->
+    entityUrl = $filter('entityUrl')
+    currency = $filter('currency')
+    percentual = $filter('percentual')
+    console.log(entity)
+    entity.unidades_orcamentarias.map (uo) ->
+      ["#{uo.label}"
+        currency(uo.amount, '')
+        percentual((uo.amount*100)/entity.autorizado.total)
+        uo.amount]

   options =
     bPaginate: false
-    aaSorting: [[ 1, 'desc' ]]
+    aaSorting: [[ 3, 'desc' ]]

   restrict: 'E',
   template: '<my-data-table columns="columns" options="options" data="data"></my-data-table>',
@@ -27,7 +32,6 @@
     scope.$watch 'entity.unidades_orcamentarias + year', ->
       [entity, year] = [scope.entity, scope.year]
       if entity? && entity.unidades_orcamentarias && year
-        scope.data = processData(entity.unidades_orcamentarias, year)
-
+        scope.data = processData(entity, year)
 ]


Put back click handler

Put back click handler

--- app/assets/javascripts/lib/mobile/autocomplete_mobile.js.coffee
+++ app/assets/javascripts/lib/mobile/autocomplete_mobile.js.coffee
@@ -65,13 +65,13 @@
       #   if @showingList
       #     @_unhideList()

-      # @$el.parentNode.addEventListener 'click', (e) =>
-      #   if e.target.tagName == 'A'
-      #     # only set the input element value if the link goes nowhere
-      #     if e.target.getAttribute('href') == '#'
-      #       e.preventDefault()
-      #       @$el.value = e.target.textContent
-      #       @_removeResults()
+      @$el.parentNode.addEventListener 'click', (e) =>
+        if e.target.tagName == 'A'
+          # only set the input element value if the link goes nowhere
+          if e.target.getAttribute('href') == '#'
+            e.preventDefault()
+            @$el.value = e.target.textContent
+            @_removeResults()

     _handleKeypress: (e) ->
       if e.keyCode == 40 # down arrow


Multiprocess works ok

Multiprocess works ok

Finishes most of the time. Some huge files mess with it.

--- lib/dscan.coffee
+++ lib/dscan.coffee
@@ -166,36 +166,28 @@
   searcher = new PathSearcher()
   regex = new RegExp(options.search, 'gi')

-  offset = 0
-  # This is terrible and unreliable and sometimes infinite loops. From:
-  # https://github.com/substack/stream-handbook#consuming-a-readable-stream
-  readLine = (stdin) ->
+  soFar = ''
+  readLines = (stdin) ->
     buf = stdin.read()
     return null unless buf

-    while offset < buf.length
-      if buf[offset] == 0x0a
-        data = buf.slice(0, offset).toString()
-        buf = buf.slice(offset + 1)
-        offset = 0
-        stdin.unshift(buf)
-        return data
-      offset++
-
-    stdin.unshift(buf);
-    null
+    # Lifted from https://github.com/dominictarr/split/blob/master/index.js
+    pieces = (soFar + buf).split('\n')
+    soFar = pieces.pop()
+    pieces

   process.stdin.on 'readable', ->
-    data = readLine(process.stdin)
-    return unless data
-
-    emitStart()
-    if data[0] == STOP_CHAR
-      emitEnd()
-    else
-      paths = JSON.parse(data)
-      searcher.searchPaths regex, paths, (results) ->
-        emitResults(results)
+    lines = readLines(process.stdin)
+    return unless lines
+
+    for line in lines
+      emitStart()
+      if !line or line[0] == STOP_CHAR
+        emitEnd()
+      else
+        paths = JSON.parse(line)
+        searcher.searchPaths regex, paths, (results) ->
+          emitResults(results)

 multiProcessSearchMain = (options) ->
   options.pathToScan = path.resolve(options.pathToScan)
@@ -234,10 +226,10 @@

   searchProcess.stdout.pipe(split()).on 'data', (line) ->
     if line[0] == START_CHAR
-      console.log "search start"
+      console.log "search start" if options.verbose
     else if line[0] == END_CHAR
       searches--
-      console.log "search end #{searches}"
+      console.log "search end #{searches}" if options.verbose
     else if line and line.length
       try
         results = JSON.parse(line)
@@ -246,7 +238,7 @@
       if results
         pathCount++
         resultCount += results.results.length
-        console.log "#{results.results.length} matches in #{results.path}"
+        console.log "#{results.results.length} matches in #{results.path}" if options.verbose

     maybeEnd()


Updated f'waifu

Updated f'waifu

--- modules/danbooru.coffee
+++ modules/danbooru.coffee
@@ -64,7 +64,7 @@
         return msg.reply "Run the #{@prefix}setWaifu command first." if not waifu?
         # Make a safebooru search
         r = await safebooru.get('/posts.json', {
-          json: true, qs: { random: true, tags: 'solo ' + waifu }
+          json: true, qs: { random: true, tags: "solo #{waifu} #{args}" }
         })
         return msg.reply 'No results.' unless r.length
         # Send the picture


Update danbooru.coffee

Update danbooru.coffee

--- modules/danbooru.coffee
+++ modules/danbooru.coffee
@@ -20,7 +20,7 @@
       # Blacklisted tags (discord community guidelines)
       # coffeelint: disable=max_line_length
       for tag in args.split(' ')
-        if tag in ['loli', 'shota', 'lolicon', 'toddlercon'] then return msg.reply '', embed: image: url: 'https://cdn.discordapp.com/attachments/244581077610397699/315655455143886850/Screenshot_from_2017-05-20_21-01-03.png'
+        if tag in ['loli', 'rori', 'shota', 'lolicon', 'toddlercon'] then return msg.reply '', embed: image: url: 'https://cdn.discordapp.com/attachments/244581077610397699/315655455143886850/Screenshot_from_2017-05-20_21-01-03.png'
         if tag in ['gore', 'guro'] then return msg.reply 'nope', embed: image: url: 'http://25.media.tumblr.com/tumblr_lqhsh2zVkZ1qjlcvoo1_500.jpg'
       # coffeelint: enable=max_line_length
       # Get a random post


fix url auto linker characters

fix url auto linker characters

--- @client/shared.coffee
+++ @client/shared.coffee
@@ -337,7 +337,7 @@
     (^|[\s\n]) # Capture the beginning of string or line or leading whitespace
     (
       (?:https?):// # Look for a valid URL protocol (non-captured)
-      [\-A-Z0-9+\u0026\u2019@#/%?=()~_|!:,.;]* # Valid URL characters (any number of times)
+      [\-A-Z0-9+\u0026\u2019@#/%?=()\[\]\-\$&\*~_|!:,.;']* # Valid URL characters (any number of times)
       [\-A-Z0-9+\u0026@#/%=~()_|] # String must end in a valid URL character
     )
   ///gi


Activity: remove log statement

Activity: remove log statement

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -60,7 +60,7 @@

   messageRemovedFromChannel: (update) ->
-    log 'messageRemovedFromChannel', update
+
     {id} = update.channelMessage

     @removeItem id


Show error when no score selected

Show error when no score selected

--- common/lib/xmodule/xmodule/js/src/capa/display.coffee
+++ common/lib/xmodule/xmodule/js/src/capa/display.coffee
@@ -209,8 +209,9 @@
     fd.append('feedback', feedback)
     fd.append('submission_id', submission_id)
     fd.append('grader_id', grader_id)
-    if(score && parseInt(score) != NaN)
-      fd.append('score', parseInt(score))
+    if(!score || parseInt(score) == NaN)
+      @gentle_alert "You need to pick a rating to submit."
+      return

     settings =


Changing single view compile to respect app config

Adjusting the single view compile functionality so that it
compiles using the adapters app.coffee config settings.

--- lib/index.coffee
+++ lib/index.coffee
@@ -132,7 +132,8 @@
         _path = "/#{compiled_file_path.replace(path.sep, '/')}"
         compiler = _.find @roots.config.compilers, (c) ->
           _.contains(c.extensions, path.extname(template).substring(1))
-        compiler.renderFile(template, _.extend(@roots.config.locals, _path: _path))
+        compiler_options = @roots.config[compiler.name] ? {}
+        compiler.renderFile(template, _.extend(@roots.config.locals, compiler_options, _path: _path))
           .then((res) => @util.write(compiled_file_path, res.result))

     __parse = (response, resolver) ->


split out constructor to build functions avoiding building unnecessary stuff and allowing overriding of them

--- lib/index.coffee
+++ lib/index.coffee
@@ -18,64 +18,87 @@

 class Cio

+  # store provided options in `_options`
   constructor: (@_options) ->

     # TODO:
     #   check for error results from all of these.
     #   set it on _error for the builder function to find and return

-    @_clientChain = buildChain()
+  _addOrdering: (chain) ->
+    chain.on 'add', markChanged
+    chain.on 'remove', markChanged
+    chain.on 'start', ensureOrdered
+    return chain
+
     @_serverChain = buildChain()
     @_serverClientChain = buildChain()

-    # order the chains
-    for chain in [ @_clientChain, @_serverChain, @_serverClientChain ]
-      chain.on 'add', markChanged
-      chain.on 'remove', markChanged
-      chain.on 'start', ensureOrdered
+  _makeChain: (listeners) ->
+
+    chain = @_addOrdering buildChain()
+    chain.add listeners
+    return chain
+
+  getClientChain: () ->
+
+    unless @_clientChain?
+
+      @_clientChain = @_makeChain [
+        # functions for building a new client
+        require './move-aliases'
+        require './secure'
+        require './ensure-certs'
+        require './create-client' # includes adding connect listener from options
+      ]
+
+    return @_clientChain

-    @_clientChain.add [
-      # functions for building a new client
-      require './move-aliases'
-      require './secure'
-      require './ensure-certs'
-      require './create-client' # includes adding connect listener from options
-    ]
+  getServerChain: () ->

-    @_serverChain.add [
-      # functions for building a new server
-      require './move-aliases'
-      require './secure'
-      require './ensure-certs'
-      require './create-server' # includes adding connect listener from options
-      require './relistener'
-      require('./emit-new-server-client') serverClientChain:@_serverClientChain
-    ]
+    unless @serverChain?

-    @_serverClientChain.add [
-      # functions for affecting a new server client
-      # no aliases cuz no cert stuff for a server client
-      # there aren't new options for this...require './combine-options'
-      # no 'secured' cuz there's no cert stuff for a server client
-      # no 'create' cuz it's created for us
-      # for secured server clients we want to authenticate them.
-      # by default everyone with a valid cert is allowed.
-      require './authenticate-client'
-    ]
+      @_serverChain = @_makeChain [
+        # functions for building a new server
+        require './move-aliases'
+        require './secure'
+        require './ensure-certs'
+        require './create-server' # includes adding connect listener from options
+        require './relistener'
+        require './emit-new-server-client'
+      ]

-    if @_options?.noRelisten then @_serverChain.disable 'cio/relistener'
+      if @_options?.noRelisten then @_serverChain.disable 'cio/relistener'

-    return
+    return @_serverChain
+
+
+  getServerClientChain: () ->
+
+    unless @_serverClientChain?
+
+      @_serverClientChain = @_makeChain [
+        # functions for affecting a new server client
+        # no aliases cuz no cert stuff for a server client
+        # there aren't new options for this...so, no combining
+        # no 'secured' cuz there's no cert stuff for a server client
+        # no 'create' cuz it's created for us
+        # for secured server clients we want to authenticate them.
+        # by default everyone with a valid cert is allowed.
+        require './authenticate-client'
+      ]
+
+    return @_serverClientChain

   client: (options) ->
-    result = @_run @_clientChain, options
+    result = @_run @getClientChain(), options
     if result.failed? then result
     else result.context.client

   server: (options) ->
-    result = @_run @_serverChain, options
+    result = @_run @getServerChain(), options
     if result.failed? then result
     else result.context.server

@@ -90,14 +113,17 @@
     # if they both exist, put the class one as a parent of the new one
     if options? and @_options? then options.__proto__ = @_options

+    # in case a listener needs the `cio` (like the emit-new-server-client)
+    runOptions.context.cio = this
+
     # call the chain
     chain.run runOptions

   # users supply listeners based on which socket they apply to.
   # use generic functions cuz it's a similar pattern
-  onClient      : (args...) -> @_fromArgs @_clientChain, args
-  onServer      : (args...) -> @_fromArgs @_serverChain, args
-  onServerClient: (args...) -> @_fromArgs @_serverClientChain, args
+  onClient      : (args...) -> @_fromArgs @getClientChain(), args
+  onServer      : (args...) -> @_fromArgs @getServerChain(), args
+  onServerClient: (args...) -> @_fromArgs @getServerClientChain(), args

   # look thru args and load stuff
   _fromArgs: (chain, args) ->


accept values provider with a get function

--- lib/index.coffee
+++ lib/index.coffee
@@ -2,6 +2,7 @@
 buildChain  = require 'chain-builder'

 class Kevas extends (require 'stream').Transform
+
   constructor: (options) ->
     super options
     @_handleExtra = @_pushString
@@ -12,10 +13,26 @@
       groups:2 # two regex groups we want
     @_key = ''

+    # if some `values` were provided
     if options?.values?
+
+      # alias
       values = options.values
-      @on 'key', (control, context) ->
-        context.values.push values[context.key] if values[context.key]?
+
+      # check if `values` has a get() function.
+      # when it does, let's consider that the way to get the values
+      if typeof values.get is 'function'
+        @on 'key', ->
+          value = values.get @key            # get the `value` from our `values`
+          if value? # when exists, add to context's `values`, as a string
+            if typeof value isnt 'string' then value = '' + value
+            @values.push value
+
+      else # otherwise, treat `values` as an object with keys
+        @on 'key', -> if values[@key]? then @values.push values[@key]
+
+    return
+

   _appendKey: (string) -> @_key += string  # accumulate key value


Tweak comment copy

Tweak comment copy

--- src/index.cjsx
+++ src/index.cjsx
@@ -62,7 +62,7 @@
       raf(@update)

   unpin: ->
-    # If component is already pinned, call onUnpin callback.
+    # If component is pinned, call onUnpin callback.
     if @state.pinned
       @props.onUnpin()


Caal function

Caal function

--- core/app/backbone/views/fact_relations/add_comment_view.coffee
+++ core/app/backbone/views/fact_relations/add_comment_view.coffee
@@ -13,7 +13,7 @@

   parseKeyDown: (e) =>
     code = e.keyCode || e.which
-    @addDefaultModel if code is 13
+    @addDefaultModel() if code is 13

   initializeModel: ->
     @model = new Comment(content: '', created_by: currentUser)


Planet Four, not Disk Detective

Planet Four, not Disk Detective

--- app/lib/en-us.coffee
+++ app/lib/en-us.coffee
@@ -27,7 +27,7 @@

Here are two other Zooniverse projects you can help with:

         Radio Galaxy Zoo
-        Disk Detective
+        Planet Four

     '''


removed custom migration script

removed custom migration script

--- filepaths_migration.coffee
+++ filepaths_migration.coffee
@@ -1,44 +0,0 @@
-require.paths.unshift './node_modules'
-require.paths.push 'server'
-
-monmon = require('monmon')
-_      = require('underscore')
-async  = require('async')
-db     = monmon.monmon.use('crash-reports')
-crashreports_db = db.collection('crashreports')
-
-read_crashreports = (cb) ->
-    crashreports_db.find().run (err,arr) ->
-        return cb err,null if err?
-        console.log "#{arr.length} crashreports read"
-        cb null, arr
-
-write_crashreports = (arr, cb) ->
-    async.forEachSeries arr,
-        (crashreport, cb_next) ->
-            console.log "store crashreport id:#{crashreport.id} to db" #debug
-            crashreports_db.find({'id':crashreport.id}).upsert().update(crashreport).run (err) ->
-                cb_next err if err?
-                cb_next null
-        (err) ->
-            cb err if err?
-            cb null
-
-modify_crashreports = (arr, cb) ->
-    arr_modified = _(arr).map (crashreport) ->
-        _(crashreport.files).each (properties,fileid) ->
-            #console.log "before:#{properties.path}"
-            properties.path = properties.path.replace /^.*\/public\//,''
-            crashreport.files["fileid"] = properties
-            #console.log "after:#{properties.path}"
-        crashreport
-    cb null, arr_modified
-
-read_crashreports (err,arr) ->
-    throw err if err?
-    modify_crashreports arr, (err,arr) ->
-        throw err if err?
-        write_crashreports arr, (err) ->
-            throw err if err?
-            monmon.closeAll()
-            console.log "done!"


wizard

wizard

--- chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
+++ chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
@@ -15,6 +15,11 @@

   Zotero.debug("[better-bibtex] #{msg.join(' ')}")
   return
+
+Zotero.BetterBibTeX.reportErrors = ->
+  ww = Components.classes['@mozilla.org/embedcomp/window-watcher;1'].getService(Components.interfaces.nsIWindowWatcher)
+  io = {}
+  win = ww.openWindow(null, 'chrome://zotero-better-bibtex/content/errorReport.xul', 'zotero-error-report', 'chrome,centerscreen,modal', io)

 Zotero.BetterBibTeX.pref = {}


chat: test and debug wildcard events

chat: test and debug wildcard events

--- client/app/Applications/Chat.kdapplication/AppController.coffee
+++ client/app/Applications/Chat.kdapplication/AppController.coffee
@@ -17,6 +17,8 @@

   handleChatOpen:({routingKey, bindingKey, publicName})->
     channel = KD.remote.mq.setP2PKeys publicName, { routingKey, bindingKey }, 'secret'
+    channel.on '*', ->
+      console.log @event, arguments

   create:(invitees, callback)->
     chatPanel = KD.getSingleton 'chatPanel'


Load last game version ONLY with a Deployd query

--- client/src/app/model/games.coffee
+++ client/src/app/model/games.coffee
@@ -96,11 +96,12 @@
   # Load the game content and the creator info, then put it all into currentGame
   load: (game) ->
     # TODO Optimize - Query for the last version only
-    getVersion = $http.get('/game-versions?gameId=' + game.id)
+    query = '{"gameId":"' + game.id + '","$sort":{"versionNumber":-1},"$limit":1}'
+    getVersion = $http.get("/game-versions?#{query}")
     getCreator = $http.get("/users?id=#{game.ownerId}")
     updateCurrentGame = ([version, creator]) ->
       currentGame.info = game
-      currentGame.version = gameConverter.convertGameVersionFromEmbeddedJson(version.data[version.data.length-1])
+      currentGame.version = gameConverter.convertGameVersionFromEmbeddedJson(version.data[0])
       currentGame.creator = creator.data.username
       console.log("loaded game", currentGame)
     onError = (error) -> console.log("Error loading game", error) # TODO: notify the user of the error


onboarding: add onclick function for bullets

--- client/home/lib/welcome/components/welcomesteps/miniview.coffee
+++ client/home/lib/welcome/components/welcomesteps/miniview.coffee
@@ -5,7 +5,7 @@

   renderBullets: ->

-

+

       {
         @props.steps.map (step, i) ->
           step = step.toJS()


adjust height, render only field for roles

--- client/lanes/access/screens/user-management/UserManagement.cjsx
+++ client/lanes/access/screens/user-management/UserManagement.cjsx
@@ -19,7 +19,7 @@
                 id="role_names"
                 key="row-select"
                 queryModel={Lanes.Models.User}
-                editOnly multiSelect writable unstyled
+                fieldOnly editOnly multiSelect writable
                 model={model}
                 labelField='name'
                 getSelection={@rolesForUser}
@@ -33,7 +33,7 @@
         <LC.ScreenWrapper identifier="user-management" flexVertical>

Users Management

             <LC.Grid
-                editorProps={height: 400, syncImmediatly: true}
+                editorProps={height: 350, syncImmediatly: true}
                 query={@state.query}
                 allowCreate
                 editor={Lanes.Access.Screens.UserManagement.Editor}


make transaction set extend Set

make transaction set extend Set

--- src/model/transaction/transaction_association_set.coffee
+++ src/model/transaction/transaction_association_set.coffee
@@ -1,18 +1,20 @@
-class Batman.TransactionAssociationSet extends Batman.Proxy
+class Batman.TransactionAssociationSet extends Batman.Set
   constructor: (associationSet, visited, stack) ->
-    super(associationSet)
+    @set('associationSet', associationSet)
     @_visited = visited
     @_stack = stack
-    @_transactionStorage = []
+    @_storage = []
     @_originalStorage = []
     @_loadOriginals(associationSet.toArray())
+
+  @delegate 'association', 'foreignKeyValue', to: 'associationSet'

   add: @mutation (items...) ->
     addedTransactions = []
     for i in items
       if i instanceof Batman.Model && !i.isTransaction
         t = i._transaction(@_visited, @_stack)
-        @_transactionStorage.push(t)
+        @_storage.push(t)
         addedTransactions.push(t)
       @_originalStorage.push(i)
     @fire 'itemsWereAdded', addedTransactions if addedTransactions.length
@@ -27,9 +29,9 @@
     removedTransactions = []
     for t in transactions
       if t.isTransaction
-        transactionIndex = @_transactionStorage.indexOf(t)
+        transactionIndex = @_storage.indexOf(t)
         if transactionIndex > -1
-          @_transactionStorage.splice(transactionIndex, 1)
+          @_storage.splice(transactionIndex, 1)
           removedTransactions.push(t)
         i = t.base()
         originalIndex = @_originalStorage.indexOf(i)
@@ -41,28 +43,15 @@
     removedTransactions

   applyChanges: (visited) ->
-    for t in @_transactionStorage
+    for t in @_storage
       t.applyChanges(visited)
     originals = new Batman.Set(@_originalStorage...)
-    target = @get('target')
+    target = @get('associationSet')
     target.replace(originals)
     target

-  toArray: -> @_transactionStorage.slice()
-
-  @accessor 'toArray', ->
-    @registerAsMutableSource?()
-    @toArray()
-
   @accessor 'length', ->
-    @registerAsMutableSource?()
-    @_transactionStorage.length
-
-  @accessor 'first', -> @toArray()[0]
-
-  forEach: (iterator, ctx) ->
-    @get('target').registerAsMutableSource?()
-    iterator.call(ctx, e, i, this) for e, i in @_transactionStorage
-    return
+    @registerAsMutableSource()
+    @_storage.length

   build: Batman.AssociationSet::build


fix room join for freenode channels

fix room join for freenode channels

I had this problem that hubot wouldn't join rooms and just idled connected to
the freenode servers. I tracked it down to the `NOTICE` message parsing. The
freenode servers would not send 'Password accepted' but rather something like
'You are now identified for ...'. I added a condition to take that into
account.

--- src/irc.coffee
+++ src/irc.coffee
@@ -61,7 +61,9 @@
       bot.addListener 'notice', (from, to, text) ->
         if from is 'NickServ' and text.indexOf('registered') isnt -1
           bot.say 'NickServ', "identify #{options.nickpass}"
-        else if options.nickpass and from is 'NickServ' and text.indexOf('Password accepted') isnt -1
+        else if options.nickpass and from is 'NickServ' and
+                (text.indexOf('Password accepted') isnt -1 or
+                 text.indexOf('identified') isnt -1)
           for room in options.rooms
             @join room


:gift: Add new keymap for add-selection only for mac

--- keymaps/vim-mode-plus.cson
+++ keymaps/vim-mode-plus.cson
@@ -139,6 +139,7 @@
   'g -': 'vim-mode-plus:dash-case'
   'g space': 'vim-mode-plus:compact-spaces'
   'g |': 'vim-mode-plus:trim-string'
+  'g cmd-d': 'vim-mode-plus:add-selection'
   # 'g _': 'vim-mode-plus:snake-case'
   # 'g r':   'vim-mode-plus:reverse'
   # 'ctrl-s': 'vim-mode-plus:transform-string-by-select-list'


small cleanups

small cleanups

--- lib/route.coffee
+++ lib/route.coffee
@@ -261,7 +261,6 @@
         url.push part

     # second pass, resolve optional parts (backwards, so later optionals are resolved first)
-    #for i=url.length-1; i>=0; i--
     for part, i in url by -1
       if part instanceof Route
         part = part.stringify params # recursion is your friend
@@ -421,8 +420,8 @@

   # parse it char by char, baby
   for char, i in string
+
     # special consideration for Ogrp starts
-
     if char == '(' && i==0
       continue # skip this char, since it's not strictly part of the route definition


removing commented code

removing commented code

--- src/scripts/modules/featured-books/featured-books.coffee
+++ src/scripts/modules/featured-books/featured-books.coffee
@@ -58,7 +58,6 @@

       # Animate the carousel to show the next featured book
       nextFeatured = () =>
-        #$container = @$el.find('.books')
         $container = $('#carousel').find('.books')
         $books = $container.find('.book')
         $first = $books.first()


Use single regex for Android Mobile

Use single regex for Android Mobile

--- coffee/lib/abstract-chosen.coffee
+++ coffee/lib/abstract-chosen.coffee
@@ -286,10 +286,9 @@
        /IEMobile/i.test(window.navigator.userAgent) or
        /Windows Phone/i.test(window.navigator.userAgent) or
        /BlackBerry/i.test(window.navigator.userAgent) or
-       /BB10/i.test(window.navigator.userAgent)
+       /BB10/i.test(window.navigator.userAgent) or
+       /Android.*Mobile/i.test(window.navigator.userAgent)
       return false
-    if /Android/i.test(window.navigator.userAgent)
-      return false if /Mobile/i.test(window.navigator.userAgent)
     if "Microsoft Internet Explorer" is window.navigator.appName
       return document.documentMode >= 8
     return true


Fjernet noen debug logginger

Fjernet noen debug logginger

--- coffee/nasjonalturbase.api.coffee
+++ coffee/nasjonalturbase.api.coffee
@@ -48,7 +48,6 @@
   res.send intro

 app.all '/:object/', (req, res) ->
-  console.log "OBJECT"
   switch req.query.method
     when 'post' then turbase.insert req, res
     when 'put' then turbase.updates req, res
@@ -56,8 +55,6 @@
     else turbase.list req, res

 app.all '/:object/:id', (req, res) ->
-  console.log "OBJECT/ID"
-  console.log req.query.method
   switch req.query.method
     when 'post' then res.send 'Error'
     when 'put' then turbase.update req, res


Hebrew translation tweak

Hebrew translation tweak

--- app/locale/he.coffee
+++ app/locale/he.coffee
@@ -1335,7 +1335,7 @@
     play_now_learn_2: "לולאות 'כל עוד' כדי לפתור פאזלים מעצבנים"
     play_now_learn_3: "מחרוזות ומשתנים להתאמה של הפעולות"
     play_now_learn_4: "כיצד להביס ענק (אלה כישורי חיים חשובים!)"
-    welcome_to_page: "לוח המחונים שלי (לתלמיד)"
+    welcome_to_page: "לוח התוצאות שלי"
     my_classes: "כיתות נוכחיות"
     class_added: "הכיתה נוספה בהצלחה!"
     view_levels: "הצג את כל השלבים בקורס"


Update ja.coffee (#6044)

Update ja.coffee (#6044)

Several translations

--- app/locale/ja.coffee
+++ app/locale/ja.coffee
@@ -5,7 +5,7 @@
 #    meta_keywords: "CodeCombat, python, javascript, Coding Games"
     meta_description: "プログラミングゲームを通してコードを学ぼう。Python、JavaScript、HTMLをパズルを解くように学んで、あなた自身のゲームやウェブサイト作りを学びましょう。"
 #    meta_og_url: "https://codecombat.com"
-#    become_investor: "to become an investor in CodeCombat"
+    become_investor: "CodeCombatの投資家になる"
 #    built_for_teachers_title: "A Coding Game Built with Teachers in Mind"
 #    built_for_teachers_blurb: "Teaching kids to code can often feel overwhelming. CodeCombat helps all educators teach students how to code in either JavaScript or Python, two of the most popular programming languages. With a comprehensive curriculum that includes six computer science units and reinforces learning through project-based game development and web development units, kids will progress on a journey from basic syntax to recursion!"
 #    built_for_teachers_subtitle1: "Computer Science"
@@ -34,7 +34,7 @@
 #    classroom_in_box_blurb3: "Inspire all school leaders to create a world-class computer science program."
 #    classroom_in_box_blurb4: ""
 #    covid19_banner_blurb: "We are offering free access to our full curriculum to educators and schools affected by school closures."
-#    click_here: "Click here"
+    click_here: "ここをクリック"
 #    creativity_rigor_title: "Where Creativity Meets Rigor"
 #    creativity_rigor_subtitle1: "Make coding fun and teach real-world skills"
 #    creativity_rigor_blurb1: "Students type real Python and JavaScript while playing games that encourage trial-and-error, critical thinking, and creativity. Students then apply the coding skills they’ve learned by developing their own games and websites in project-based courses."
@@ -215,7 +215,7 @@
   modal:
     close: "閉じる"
     okay: "OK"
-#    cancel: "Cancel"
+    cancel: "取り消し"

   not_found:
     page_not_found: "ページが見つかりません"
@@ -869,9 +869,9 @@
     restricted: "(このレベルでは制限品)"
     equip: "装備する"
     unequip: "装備を外す"
-#    warrior_only: "Warrior Only"
-#    ranger_only: "Ranger Only"
-#    wizard_only: "Wizard Only"
+    warrior_only: "Warrior のみ"
+    ranger_only: "Ranger のみ"
+    wizard_only: "Wizard のみ"

   buy_gems:
     few_gems: "少し購入"


Adding .coverage suffix as necessary

Adding .coverage suffix as necessary

--- src/pipe/umd/index.coffee
+++ src/pipe/umd/index.coffee
@@ -55,6 +55,9 @@
           (
             lib.pipe.lazypipe()
             .pipe -> transpile(options.transpile, { coffeeScript: null })
+            .pipe -> lib.metadata.rename({
+              suffix: '.coverage'
+            })
             .pipe -> module.exports(options)
           )()
         )


Update sk.coffee

Update sk.coffee

Translated share_progress_modal

--- app/locale/sk.coffee
+++ app/locale/sk.coffee
@@ -1,20 +1,20 @@
 module.exports = nativeDescription: "slovenčina", englishDescription: "Slovak", translation:
   home:
     slogan: "Nauč sa programovať pomocou hry"
-    no_ie: "CodeCombat nefunguje v prehliadači Internet Explorer 8 a jeho starších verziách. Ospravedlňujeme sa." # Warning that only shows up in IE8 and older
-    no_mobile: "CodeCombat nebol navrhnutý pre mobilné zariadenia a nemusí na nich fungovať správne!" # Warning that shows up on mobile devices
-    play: "Hraj" # The big play button that opens up the campaign view.
-    old_browser: "Ajaj, prehliadač je príliš starý. CodeCombat na ňom nepôjde. Je nám to ľúto!" # Warning that shows up on really old Firefox/Chrome/Safari
+    no_ie: "CodeCombat nefunguje v prehliadači Internet Explorer 8 a jeho starších verziách. Ospravedlňujeme sa."
+    no_mobile: "CodeCombat nebol navrhnutý pre mobilné zariadenia a nemusí na nich fungovať správne!"
+    play: "Hraj"
+    old_browser: "Ajaj, prehliadač je príliš starý. CodeCombat na ňom nepôjde. Je nám to ľúto!"
     old_browser_suffix: "Skúsiť sa to dá, ale asi to nepôjde."
     ipad_browser: "Zlé správy: CodeCombat nebeží na iPade v prehliadači. Dobré správy: naša iPad aplikácia čaká na schválenie od Apple."
     campaign: "Kampaň"
     for_beginners: "Pre začiatočníkov"
-    multiplayer: "Viac hráčov" # Not currently shown on home page
-    for_developers: "Pre vývojárov" # Not currently shown on home page.
+    multiplayer: "Viac hráčov"
+    for_developers: "Pre vývojárov"
     or_ipad: "Alebo stiahni pre iPad"

   nav:
-    play: "Hraj" # The top nav bar entry where players choose which levels to play
+    play: "Hraj"
     community: "Komunita"
     editor: "Editor"
     blog: "Blog"
@@ -23,7 +23,7 @@
     profile: "Profil"
     stats: "Štatistiky"
     code: "Kód"
-    admin: "Spravuj" # Only shows up when you are an admin
+    admin: "Spravuj"
     home: "Domov"
     contribute: "Prispej"
     legal: "Pre právnikov"
@@ -40,7 +40,7 @@
     page_not_found: "Stránka nenájdená"

   diplomat_suggestion:
-    title: "Pomôžte preložiť CodeCombat!" # This shows up when a player switches to a non-English language using the language selector.
+    title: "Pomôžte preložiť CodeCombat!"
     sub_heading: "Potrebujeme tvoje jazykové zručnosti."
     pitch_body: "We develop CodeCombat in English, but we already have players all over the world. Many of them want to play in Slovak but don't speak English, so if you can speak both, please consider signing up to be a Diplomat and help translate both the CodeCombat website and all the levels into Slovak."
     missing_translations: "Until we can translate everything into Slovak, you'll see English when Slovak isn't available."
@@ -48,25 +48,25 @@
     subscribe_as_diplomat: "Prihlásiť sa ako Diplomat"

   play:
-    play_as: "Hraj ako" # Ladder page
-    spectate: "Sledovať" # Ladder page
-    players: "hráči" # Hover over a level on /play
-    hours_played: "odohratých hodín" # Hover over a level on /play
-    items: "Predmety" # Tooltip on item shop button from /play
-    unlock: "Odomknúť" # For purchasing items and heroes
+    play_as: "Hraj ako"
+    spectate: "Sledovať"
+    players: "hráči"
+    hours_played: "odohratých hodín"
+    items: "Predmety"
+    unlock: "Odomknúť"
     confirm: "Potvrdiť"
-    owned: "Vlastníš" # For items you own
+    owned: "Vlastníš"
     locked: "Zamknuté"
-    purchasable: "Môžeš zakúpiť" # For a hero you unlocked but haven't purchased
+    purchasable: "Môžeš zakúpiť"
     available: "Dostupné"
-    skills_granted: "Získané skúsenosti" # Property documentation details
-    heroes: "Hrdinovia" # Tooltip on hero shop button from /play
-    achievements: "Úspechy" # Tooltip on achievement list button from /play
-    account: "Účet" # Tooltip on account button from /play
-    settings: "Nastavenia" # Tooltip on settings button from /play
-#    poll: "Poll" # Tooltip on poll button from /play
-    next: "Ďalší" # Go from choose hero to choose inventory before playing a level
-    change_hero: "Zmeniť hrdinu" # Go back from choose inventory to choose hero
+    skills_granted: "Získané skúsenosti"
+    heroes: "Hrdinovia"
+    achievements: "Úspechy"
+    account: "Účet"
+    settings: "Nastavenia"
+    poll: "Výzva"
+    next: "Ďalší"
+    change_hero: "Zmeniť hrdinu"
     choose_inventory: "Vyzbrojiť sa s predmetmy"
     buy_gems: "Zakúpiť drahokamy"
     subscription_required: "Vyžaduje sa rredplatné"
@@ -78,7 +78,7 @@
     awaiting_levels_adventurer: "Prihlás sa ako Dobrodruh"
     awaiting_levels_adventurer_suffix: "budeš ako prvý hrať nové levely."
     adjust_volume: "Zmeniť hlasitosť"
-    choose_your_level: "Vyber si úroveň" # The rest of this section is the old play view at /play-old and isn't very important.
+    choose_your_level: "Vyber si úroveň"
     adventurer_prefix: "Môže si vybrať ktorúkoľvek z úrovní alebo ich prediskutovať na "
     adventurer_forum: "fóre pre dobrodruhov"
     adventurer_suffix: "."
@@ -93,15 +93,15 @@
     campaign_classic_algorithms: "Klasické Algoritmy"
     campaign_classic_algorithms_description: "... v kterých sa naučíte najobľúbenejšie algoritmy v IT"

-#  share_progress_modal:
-#    blurb: "You’re making great progress! Tell someone how much you've learned with CodeCombat."
-#    email_invalid: "Email address invalid."
-#    form_blurb: "Enter their email below and we’ll show them!"
-#    form_label: "Email Address"
-#    placeholder: "email address"
-#    title: "Excellent Work, Apprentice"
-#    tell_friend: "Tell your Friend"
-#    tell_parent: "Tell your Parent"
+  share_progress_modal:
+    blurb: "Robíš veľké pokroky! Povedz niekomu o tom, čo si sa naučil cez CodeCombat."
+    email_invalid: "Neplatná emailová adresa."
+    form_blurb: "Zadaj email priateľa a mi mu to oznámime!"
+    form_label: "Emailová adresa"
+    placeholder: "emailová adresa"
+    title: "Skvelá práca, učeň"
+    tell_friend: "Povedz svojmu priateľovi"
+    tell_parent: "Povedz svojím rodičom"

   login:
     sign_up: "Vytvor účet"


Visual/edit modes: really fix restore of insert-mode sub mode.

--- content_scripts/mode.coffee
+++ content_scripts/mode.coffee
@@ -151,10 +151,11 @@
   # case), because they do not need to be concerned with the value they yield.
   alwaysContinueBubbling: handlerStack.alwaysContinueBubbling

-  # Get a copy of the configuration options for this mode (that is, excluding the main keyboard-event
-  # handlers).
+  # Get a copy of the configuration options for this mode, but excluding the main keyboard-event handlers.
   getConfigurationOptions: ->
-    extend (extend {}, @options), keydown: null, keypress: null, keyup: null
+    options = extend {}, @options
+    delete options[key] for key in [ "keydown", "keypress", "keyup" ]
+    options

   # Static method.  Used externally and internally to initiate bubbling of an updateBadge event and to send
   # the resulting badge to the background page.  We only update the badge if this document (hence this frame)


Display duplicate id errors

Display duplicate id errors

--- tutor/src/components/course-settings/undrop-student.cjsx
+++ tutor/src/components/course-settings/undrop-student.cjsx
@@ -18,18 +18,43 @@
   isUnDropping: ->
     RosterStore.isUnDropping(@props.student.id)

-  confirmPopOver: ->
-    title =
-      if @isUnDropping()
+  errorMessage: (error) ->
+    if error.code is 'student_identifier_has_already_been_taken'
+      title: "Student ID is in use",
+      body:

-           Adding...
+          Unable to re-activate <Name {...@props.student} /> while
+          another student is using the same student ID.
+          Please update either this student's ID or change the other's
+          so there is no longer a conflict

-      else
-        Add <Name {...@props.student} />?
-    <BS.Popover title={title} {...@props}>
+    else
+      title: "Error occured",
+      body: "An error #{error.code} #{error.message} has occured"
+
+  inProgressMessage: ->
+    title: "Restoring student",
+    body:  <Icon type='spinner' spin /> In progress
+
+
+  popOverMessage: ->
+    title: Add <Name {...@props.student} />?
+    body:
       <BS.Button className='-undrop-student' onClick={@performDeletion} bsStyle="success">
         <Icon type='plus' /> Add
       </BS.Button>
+
+  confirmPopOver: ->
+    error = RosterStore.getError(@props.student.id)
+    {title, body} = if error
+      @errorMessage(error)
+    else if @isUnDropping()
+      @inProgressMessage()
+    else
+      @popOverMessage()
+
+    <BS.Popover title={title} {...@props} className='undrop-student'>
+      {body}
     </BS.Popover>

   render: ->


Fix for Coffeelint

Fix for Coffeelint

--- _includes/coffee/essential.coffee
+++ _includes/coffee/essential.coffee
@@ -414,7 +414,7 @@

 get_or = curry(
   (key, def, dict) ->
-    get(key, dict) || def
+    get(key, dict) or def
 )


answer, not additional

answer, not additional

--- src/pow/dns_server.coffee
+++ src/pow/dns_server.coffee
@@ -21,8 +21,8 @@

     q = req.question[0] ? {}

-    if q.type is ndns.ns_t.a and q["class"] is ndns.ns_c.in and @pattern.test q.name
-      res.addRR ndns.ns_s.ar, q.name, ndns.ns_t.a, ndns.ns_c.in, 600, "127.0.0.1"
+    if q.type is ndns.ns_t.a and q.class is ndns.ns_c.in and @pattern.test q.name
+      res.addRR ndns.ns_s.an, q.name, ndns.ns_t.a, ndns.ns_c.in, 600, "127.0.0.1"
     else
       res.header.rcode = ndns.ns_rcode.nxdomain


Set Atom Dark as the default theme

Set Atom Dark as the default theme

--- config.cson
+++ config.cson
@@ -10,8 +10,8 @@
     ]
     telemetryConsent: "limited"
     themes: [
-      "one-dark-ui"
-      "zenburn-theme"
+      "atom-dark-ui"
+      "atom-dark-syntax"
     ]
   "default-language":
     defaultLanguage: "Pandoc markdown"


Default to /dev/null device. It's now easier to use this as simulator.

--- config.cson
+++ config.cson
@@ -5,7 +5,8 @@
   hosts:
     enttec1:
       # path: "/dev/serial/by-id/usb-FTDI_FT245R_USB_FIFO_ENP9D7H7-if00-port0"
-      path: "/dev/serial/by-id/usb-FTDI_USB__-__Serial-if00-port0"
+      # path: "/dev/serial/by-id/usb-FTDI_USB__-__Serial-if00-port0"
+      path: "/dev/null"
       type: "enttec"
   mapping:
     light:


Add -syntax suffix to converted themes

Add -syntax suffix to converted themes

--- tasks/convert-theme.coffee
+++ tasks/convert-theme.coffee
@@ -10,7 +10,8 @@
       textMateThemePath = path.resolve(textMateThemePath)
       if grunt.file.isFile(textMateThemePath)
         textMateTheme = new TextMateTheme(textMateThemePath)
-        atomThemePath = path.join(path.dirname(textMateThemePath), "#{path.basename(textMateThemePath, path.extname(textMateThemePath))}.css")
+        themeName = path.basename(textMateThemePath, path.extname(textMateThemePath))
+        atomThemePath = path.join(path.dirname(textMateThemePath), "#{themeName.toLowerCase()}-syntax.css")
         grunt.file.write(atomThemePath, textMateTheme.getStylesheet())
         grunt.log.ok("Atom theme written to: #{atomThemePath}")
       else


Updated

Updated

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -22,7 +22,7 @@
   @guid = -> return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4())

   # parse an object whose values are still JSON stringified
-  @parseRawQuery: (query) ->
+  @parseJSON: (query) ->
     return JSON.parse(query) if _.isString(query)
     result = {}
     for key, value of query


:art: new util, determine cursor is at first character of line

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -225,6 +225,19 @@

 getLastVisibleScreenRow = (editor) ->
   getView(editor).getLastVisibleScreenRow()
+
+getFirstCharacterColumForBufferRow = (editor, row) ->
+  text = editor.lineTextForBufferRow(row)
+  if (column = text.search(/\S/)) >= 0
+    column
+  else
+    null
+
+cursorIsAtFirstCharacter = (cursor) ->
+  {editor} = cursor
+  column = cursor.getBufferColumn()
+  firstCharColumn = getFirstCharacterColumForBufferRow(editor, cursor.getBufferRow())
+  firstCharColumn? and column is firstCharColumn

 # Cursor motion wrapper
 # -------------------------
@@ -426,6 +439,8 @@
   getCodeFoldRowRanges
   getCodeFoldRowRangesContainesForRow
   getBufferRangeForRowRange
+  getFirstCharacterColumForBufferRow
+  cursorIsAtFirstCharacter

   # Debugging
   reportSelection,


Encode image file name

Encode image file name

--- frontend/coffee/app.coffee
+++ frontend/coffee/app.coffee
@@ -136,7 +136,7 @@

#{item.name}

-
<input class="form-control" type="text" value="![#{item.name}](#{item.name})" onclick="this.select()" readonly>

+
<input class="form-control" type="text" value="![#{item.name}](#{encodeURIComponent item.name})" onclick="this.select()" readonly>


Compose tweet message based on available info

--- framer/Components/ShareComponent.coffee
+++ framer/Components/ShareComponent.coffee
@@ -416,10 +416,24 @@
 			style:
 				backgroundImage: "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAABGdBTUEAALGPC/xhBQAAAO1JREFUOBFjZMABWltbJX///l0GlDYAYg1GRkZxIP3n////P4E0EyOQwABNTU05QAVtQMyLIQkVwNDY3Nzs9vfv3524NMDEmWAMED1z5kyuf//+zUEWw8VG0fjq1SsnoPNkcSlGFmdB5gA16SHzQWxgoPxnZma2UVNTOxkWFvYXJo+uUQwmAaOBhn2tqak5BuPDaBSnAhXJwySQaB4kNpyJohEoqgCXIcAgWyNjQ0PDfwKGY0gDA+w5uo0YirAJAMPiLFkagTaeIUsjExMTeTaCNGIkcmyBBRTDUEeWU0EBNqoRW7KBio0GDi0CBwAHJ0YrwGtXbwAAAABJRU5ErkJggg==')"

+		# Generate tweet
+
+		tweet = ""
+		if @shareInfo.twitter or @shareInfo.author
+			tweet += "A prototype by "
+
+			if @shareInfo.twitter
+				tweet += "@" + @shareInfo.twitter
+			else if @shareInfo.author
+				tweet += @shareInfo.author
+
+			tweet += ". "
+
+		tweet += "Design without limitations in @framerjs — #{window.location.href}"
+		tweet = encodeURIComponent(tweet)
+
 		@buttonTwitter = new Button
-			url: """
-				https://twitter.com/home?status=Check%20out%20this%20prototype%20made%20in%20%40framerjs%20%E2%80%94%20#{window.location.href}
-			"""
+			url: "https://twitter.com/home?status=#{tweet}"
 			parent: @buttons
 			borderWidth: 1
 			borderColor: "#D5D5D5"


Fixed stepping.

Fixed stepping.

--- scripts/debugger.coffee
+++ scripts/debugger.coffee
@@ -70,10 +70,18 @@

 		$('#step').click =>
 			return if @running
-			ret = @run_one()
-			@center = if @cpu.delay == null then @cpu.pc else @cpu.delay
-			@update true
-			throw ret if ret != null
+			e = null
+			try
+				@run_one()
+			catch e
+
+			finally
+				@center = if @cpu.delay == null then @cpu.pc else @cpu.delay
+				@update true
+			if e != null
+				if e instanceof Exception
+					return
+				throw e

 		$('#add-bp').click =>
 			return if $('#new-bp-addr').val() == ''


Update entrance.coffee

Update entrance.coffee

high_twerk's needs an emphatic entrance

--- scripts/entrance.coffee
+++ scripts/entrance.coffee
@@ -10,3 +10,5 @@
       msg.send "Bazinga!"
     else if /shyguy/.test(username)
       msg.send "wb #{username}"
+    else if /high_twerk/.test(username)
+      msg.send "wb #{username}!!!!!!!"


Fix list sorting.

Fix list sorting.

--- app/assets/javascripts/CartoCMS/resources.js.coffee
+++ app/assets/javascripts/CartoCMS/resources.js.coffee
@@ -35,8 +35,9 @@

   # Positionable
   $('ul#positionable').sortable
-   axis: 'y'
-   handle: '.handle'
-   placeholder: 'placeholder'
-   update: ->
-     $.post($(this).data('position_url'), $(this).sortable('serialize'))+    axis: 'y'
+    handle: '.handle'
+    placeholder: 'placeholder'
+    update: ->
+      $.post($(this).data('position-url'), $(this).sortable('serialize'))
+


Reorganize `mb.alerts` module.

Reorganize `mb.alerts` module.

--- app/assets/javascripts/app/modules/alerts.js.coffee
+++ app/assets/javascripts/app/modules/alerts.js.coffee
@@ -1,4 +1,42 @@
 alerts = angular.module("mb.alerts", [])
+
+class Alerts
+  @$inject = ["$log", "$timeout", "alertTimeout"]
+  constructor: (@$log, @$timeout, @alertTimeout) ->
+    @lastId = 0
+    @messages = []
+
+  # Returns a next id for the new message
+  nextId: ->
+    @lastId += 1
+
+  push: (type, text) ->
+    id = @nextId()
+    @$log.info("Alert [#{id}, #{type}]", text)
+
+    @messages.push(id: id, type: type, text: text)
+    @delayedDispose(id)
+
+    id
+
+  # Helper methods for various alerts types
+  info: (text) -> @push("info", text)
+  error: (text) -> @push("error", text)
+
+  # Disposes a message with the given id
+  dispose: (id) ->
+    at = @messages.map((message) -> message.id).indexOf(id)
+    @messages.splice(at, 1)
+
+  # Dispose the message after the given time in milliseconds
+  delayedDispose: (id) ->
+    if @alertTimeout? and @alertTimeout > 0
+      disposeTheAlert = =>
+        @$log.info("Disposing alert", id, "after", @alertTimeout, "milliseconds")
+        @dispose(id)
+      @$timeout(disposeTheAlert, @alertTimeout)
+
+alerts.service "alerts", Alerts

 class AlertsCtrl
   @$inject = ["$scope", "alerts"]
@@ -10,43 +48,6 @@

 alerts.controller "alerts", AlertsCtrl

-# TODO figure out how to create coffeescript class for services
-alerts.factory "alerts", [
-  "$log", "$timeout", "alertTimeout", ($log, $timeout, alertTimeout) ->
-    lastId: 0
-    messages: []
-
-    # Returns a next id for the new message
-    nextId: ->
-      @lastId += 1
-
-    push: (type, text) ->
-      id = @nextId()
-      $log.info("Alert [#{id}, #{type}]", text)
-
-      @messages.push(id: id, type: type, text: text)
-      @delayedDispose(id)
-
-      id
-
-    # Helper methods for various alerts types
-    info: (text) -> @push("info", text)
-    error: (text) -> @push("error", text)
-
-    # Disposes a message with the given id
-    dispose: (id) ->
-      at = @messages.map((message) -> message.id).indexOf(id)
-      @messages.splice(at, 1)
-
-    # Dispose the message after the given time in milliseconds
-    delayedDispose: (id) ->
-      if alertTimeout? and alertTimeout > 0
-        disposeTheAlert = =>
-          $log.info("Disposing alert", id, "after", alertTimeout, "milliseconds")
-          @dispose(id)
-        $timeout(disposeTheAlert, alertTimeout)
-]
-
 alerts.directive "alerts", ->
   restrict: "E"
   transclude: true


clean up switch statement

clean up switch statement

--- tutor/src/components/student-dashboard/events-panel.cjsx
+++ tutor/src/components/student-dashboard/events-panel.cjsx
@@ -40,13 +40,15 @@
       key:        event.id
       event:      event

-    switch event.type
-      when 'reading'  then <ReadingRow {...rowProps}/>
-      when 'homework' then <HomeworkRow {...rowProps}/>
-      when 'external' then <ExternalRow {...rowProps}/>
-      when 'event' then <EventTaskRow {...rowProps}/>
+    Row = switch event.type
+      when 'reading'  then  ReadingRow
+      when 'homework' then  HomeworkRow
+      when 'external' then  ExternalRow
+      when 'event'    then  EventTaskRow
       else
-        <GenericEventRow {...rowProps}/>
+        GenericEventRow
+
+    <Row {...rowProps}/>

   render: ->
     <BS.Panel className={@props.className}>


Remove the Debug_level setting as well

Remove the Debug_level setting as well

--- packages/rocketchat-lib/server/startup/settings.coffee
+++ packages/rocketchat-lib/server/startup/settings.coffee
@@ -221,7 +221,6 @@

 RocketChat.settings.addGroup 'Logs', ->
-	@add 'Debug_Level', 'error', { type: 'select', values: [ { key: 'error', i18nLabel: 'Only_errors' }, { key: 'debug', i18nLabel: 'All_logs' } ] }
 	@add 'Log_Level', '0', { type: 'select', values: [ { key: '0', i18nLabel: '0_Errors_Only' }, { key: '1', i18nLabel: '1_Errors_and_Information' }, { key: '2', i18nLabel: '2_Erros_Information_and_Debug' } ] , public: true }
 	@add 'Log_Package', false, { type: 'boolean', public: true }
 	@add 'Log_File', false, { type: 'boolean', public: true }


Tweak comments re. keydown versus keypress.

--- content_scripts/link_hints.coffee
+++ content_scripts/link_hints.coffee
@@ -391,10 +391,11 @@

   constructor: ->
     @linkHintCharacters = Settings.get "linkHintCharacters"
-    # We use the keyChar from keydown if the link-hint characters are all "a-z".  This is the default, and
-    # preserves the legacy behavior (which always used keydown) for users which are familiar with that
-    # behavior.  Otherwise, we use keyChar from keypress, which admits non-Latin characters. See #1722.
-    @useKeydown = /^[a-z]*$/.test @linkHintCharacters
+    # We use the keyChar from keydown if the link-hint characters are all "a-z0-9".  This is the default
+    # settings value, and preserves the legacy behavior (which always used keydown) for users which are
+    # familiar with that behavior.  Otherwise, we use keyChar from keypress, which admits non-Latin
+    # characters. See #1722.
+    @useKeydown = /^[a-z0-9]*$/.test @linkHintCharacters
     @activateOnEnter = false
     @hintKeystrokeQueue = []

@@ -537,6 +538,9 @@
     { linksMatched: linksMatched, delay: delay }

   pushKeyChar: (keyChar, keydownKeyChar) ->
+    # For filtered hints, we *always* use the keyChar value from keypress, because there is no obvious and
+    # easy-to-understand meaning for choosing one of keyChar or keydownKeyChar (as there is for alphabet
+    # hints).
     if 0 <= @linkHintNumbers.indexOf keyChar
       @hintKeystrokeQueue.push keyChar
     else


Simplify hint-string generation; tweaks.

--- content_scripts/link_hints.coffee
+++ content_scripts/link_hints.coffee
@@ -440,11 +440,6 @@
   # may be of different lengths.
   #
   hintStrings: (linkCount) ->
-    return [] if linkCount == 0
-
-    # In the following:
-    #   - at no point is any hint in hints a prefix of any other hint
-    #   - the shorter hints are always at the start of the list
     hints = [""]
     offset = 0
     while hints.length - offset < linkCount or hints.length == 1
@@ -453,9 +448,9 @@
     hints = hints[offset...offset+linkCount]

     # This shuffles the hints so that they're scattered; hints starting with the same character are spread
-    # evenly throughout the array.  We reverse each hint, then sort them then reverse again.
+    # evenly throughout the array.  We reverse each hint, then sort them, then reverse them again.
     hints = (hint.split("").reverse().join "" for hint in hints).sort()
-    return (hint.split("").reverse().join "" for hint in hints[...linkCount])
+    return (hint.split("").reverse().join "" for hint in hints)

   getMatchingHints: (hintMarkers) ->
     matchString = @hintKeystrokeQueue.join ""


dimensions could be undefined.

dimensions could be undefined.

--- src/app/window.coffee
+++ src/app/window.coffee
@@ -37,7 +37,7 @@
     requireStylesheet(nativeStylesheetPath)

   dimensions = atom.getWindowState('dimensions')
-  dimensions = defaultWindowDimensions unless dimensions.width and dimensions.height
+  dimensions = defaultWindowDimensions unless dimensions?.width and dimensions?.height
   window.setDimensions(dimensions)
   remote.getCurrentWindow().show()
   $(window).on 'unload', -> atom.setWindowState('dimensions', window.getDimensions())


empty rejection is a thing

empty rejection is a thing

--- resources/assets/lib/store-checkout.coffee
+++ resources/assets/lib/store-checkout.coffee
@@ -60,14 +60,10 @@
                   Promise.resolve()

       promise.catch (error) ->
-        console.error(error)
         LoadingOverlay.hide()
         # TODO: less unknown error, disable button
         # TODO: handle error.message
-        if error.xhr
-          osu.ajaxError(error.xhr)
-        else
-          osu.ajaxError()
+        osu.ajaxError(error?.xhr)

   @allTraps: ->
     traps = {}


Fix remaining duplicates

Fix remaining duplicates

--- dev/us.cson
+++ dev/us.cson
@@ -337,16 +337,7 @@
     { type: 'height_value', color: 'black'}
   ]

-'traffic-merges-right-ahead':
-  category: 'warning'
-  name: 'merge'
-  elements: [
-    { type: 'square-rounded', color: 'black', transform: '{square_to_diamond}' }
-    { type: 'square-rounded', color: 'yellow', transform: 'scale(.95) {square_to_diamond}' }
-    { type: 'merge', color: 'black' }
-  ]
-
-'height-restriction-ahead':
+'height-restriction-ahead_v2':
   category: 'warning'
   name: 'Height restriction ahead'
   variation: 'meters'
@@ -355,6 +346,15 @@
     { type: 'square-rounded', color: 'yellow', transform: 'scale(.95) {square_to_diamond}' }
     { type: 'height', color: 'black' }
     { type: 'height_value', color: 'black'}
+  ]
+
+'traffic-merges-right-ahead':
+  category: 'warning'
+  name: 'merge'
+  elements: [
+    { type: 'square-rounded', color: 'black', transform: '{square_to_diamond}' }
+    { type: 'square-rounded', color: 'yellow', transform: 'scale(.95) {square_to_diamond}' }
+    { type: 'merge', color: 'black' }
   ]

 'motorcycle-crossing':
@@ -819,7 +819,7 @@
     { type: 'children', color: 'black' }
   ]

-'school':
+'school_v2':
   category: 'school'
   name: 'school'
   variation: 'obsolete'


Fix some minor email address detection.

Fix some minor email address detection.


fixes 48

fixes 48

--- lib/client.coffee
+++ lib/client.coffee
@@ -25,7 +25,7 @@
           delete @callbackMap[callId]

       else
-        generalMsgHandler(json) # We let swank leak for now because I don't really know how (:clear-scala-notes) should
+        generalMsgHandler(json.payload) # We let swank leak for now because I don't really know how (:clear-scala-notes) should
         # be translated into json. So unfortunately direct deps from main to car/cdr and such.
     )


Fix ASTLinter to report lineNumber correctly with 1.6.2+ CoffeeScript

--- src/coffeelint.coffee
+++ src/coffeelint.coffee
@@ -781,7 +781,10 @@
         # Parse the line number
         lineNumber = -1
         match = /line (\d+)/.exec message
-        lineNumber = parseInt match[1], 10 if match?.length > 1
+        if coffeeError.location?
+          lineNumber = coffeeError.location.first_line
+        else
+          lineNumber = parseInt match[1], 10 if match?.length > 1
         attrs = {
             message: message
             level: rule.level


add toBePresent matcher

add toBePresent matcher

--- test/customMatchers.coffee
+++ test/customMatchers.coffee
@@ -130,3 +130,9 @@
             arraysEqual(keysOf(actual), ['is', 'value', 'defined']) &&
             type(actual.is) == 'function'
           result
+
+      toBePresent: (util, customEqualityTesters)->
+        return compare: (actual, expected)->
+          result = {}
+          result.pass = eval("typeof #{actual} !== 'undefined' && #{actual} !== null;")
+          result


Add de TODOs

Add de TODOs

--- dev/de.cson
+++ dev/de.cson
@@ -177,3 +177,474 @@
     { type: 'square-rounded', color: 'white', transform: 'scale(.95, .45)'}
     { type: 'DE-arrow-up', color: 'black', transform: 'scale(.6) rotate(90deg)'}
   ]
+
+
+
+
+  category: 'information'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+
+DANGER
+'unprotected-quayside-or-riverbank':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'wild-animals':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'double-curve-first-left':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'double-curve-first-right':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'curve-left':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'curve-right':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'crossroads-with-priority-to-the-right':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'cyclists-crossing-ahead':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'other-danger':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'crossroads-ahead':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'junction-with-a-side-road-perpendicular-left':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'junction-with-a-side-road-perpendicular-right':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'pedestrian-crossing':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'road-bump':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'road-narrows-ahead':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'road-narrows-left-ahead':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'road-narrows-right-ahead':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'roadworks-ahead':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'roundabout-ahead':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'children':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'slippery-road-surface':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'traffic-signals-ahead':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'two-way-traffic-ahead':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'uneven-road-ahead':
+  category: 'danger'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+
+INFORMATION
+'bus-stop':
+  category: 'information'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'disabled-persons':
+  category: 'information'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'parking':
+  category: 'information'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'pedestrian-crossing':
+  category: 'information'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+
+MANDATORY
+'dual-path-pedestrians-and-cyclists':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'bicycles-only':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'pedestrians-only':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'turn-left':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'pass-on-either-side':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'proceed-straight-or-turn-left':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'turn-right':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'proceed-straight-or-turn-right':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'proceed-straight':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'pass-on-this-side-left':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'pass-on-this-side-right':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'dual-path-cyclists-and-pedestrians':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'shared-path-pedestrians-and-cyclists':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'roundabout':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'turn-left-ahead':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'turn-right-ahead':
+  category: 'mandatory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+
+PRIORITY
+'give-way':
+  category: 'priority'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'priority-road':
+  category: 'priority'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'give-way-to-oncoming-traffic':
+  category: 'priority'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'stop':
+  category: 'priority'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-entry':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-motor-vehicles':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-motorcycles':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-parking':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-stopping-or-parking':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-traffic-both-ways':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-heavy-goods-vehicles':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-u-turn':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-vehicles-carrying-dangerous-goods':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-left-turn':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-right-turn':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-overtaking':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'no-overtaking-by-heavy-goods-vehicles':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'maximum-speed-limit':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'maximum-height':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]
+
+'maximum-width':
+  category: 'prohibitory'
+  name: ''
+  elements: [
+    { type: 'circle-bg', color: 'black'}
+  ]


Fixed several existing signs (`us.cson`)

Applied the new transformations, beautified signs and removed
duplicates.

--- dev/us.cson
+++ dev/us.cson
@@ -18,7 +18,8 @@
   category: 'warning'
   name: 'merge'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'merge', value: 'black' }
   ]

@@ -26,7 +27,8 @@
   category: 'warning'
   name: 'pedestrian crossing'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'pedestrian', value: 'black' }
   ]

@@ -34,7 +36,8 @@
   category: 'warning'
   name: 'traffic light'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'traffic-l-bg', value: 'black' }
     { type: 'traffic-l-bottom', value: 'green' }
     { type: 'traffic-l-middle', value: 'yellow' }
@@ -47,50 +50,36 @@
   elements: [
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
-    { type: 'parking fit', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'parking', value: 'black', transform: '{fit_border_circle}' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 warning_road_narrows_right:
   category: 'warning'
   name: 'road narrows right'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'narrow-road-r fit', value: 'black' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+    { type: 'narrow-road-l', value: 'black', transform: '{fit_diamond} scale(-1,1)' }
   ]

 warning_road_narrows_left:
   category: 'warning'
   name: 'road narrows left'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'narrow-road-l fit', value: 'black' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+    { type: 'narrow-road-l', value: 'black', transform: '{fit_diamond}' }
   ]

 warning_road_narrows_both:
   category: 'warning'
   name: 'road narrows both'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'narrow-road-both fit', value: 'black' }
-  ]
-
-warning_turn_curve_left:
-  category: 'warning'
-  name: 'curve turn left'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'turn-l', value: 'black' }
-  ]
-
-warning_turn_curve_right:
-  category: 'warning'
-  name: 'curve turn right'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'turn-r', value: 'black' }
-  ]
-
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+    { type: 'narrow-road-both', value: 'black', transform: '{fit_diamond}' }
+  ]

 regulatory_no_bicycles:
   category: 'regulatory'
@@ -98,8 +87,8 @@
   elements: [
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
-    { type: 'bicycle fit', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'bicycle', value: 'black', transform: '{fit_border_circle}' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 regulatory_no_left_turn:
@@ -108,8 +97,8 @@
   elements: [
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
-    { type: 'turn-90-l fit', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'turn-90-l', value: 'black', transform: '{fit_border_circle}' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 regulatory_no_turn_right:
@@ -118,8 +107,8 @@
   elements: [
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
-    { type: 'turn-90-r fit', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'turn-90-l', value: 'black', transform: '{fit_border_circle} scale(-1,1)' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 regulatory_no_u_turn:
@@ -128,15 +117,16 @@
   elements: [
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
-    { type: 'u-turn fit', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'u-turn', value: 'black', transform: '{fit_border_circle}' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 warning_added_lanes:
   category: 'warning'
   name: 'added lanes'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'added-lanes', value: 'black' }
   ]

@@ -144,7 +134,8 @@
   category: 'warning'
   name: 'cross roads'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'cross-roads', value: 'black' }
   ]

@@ -152,7 +143,8 @@
   category: 'warning'
   name: 'side road perpendicular right'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'side-road-p-r', value: 'black' }
   ]

@@ -160,7 +152,8 @@
   category: 'warning'
   name: 'side road perpendicular left'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'side-road-p-l', value: 'black' }
   ]

@@ -170,23 +163,25 @@
   elements: [
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
-    { type: 'truck fit', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'truck', value: 'black', transform: '{fit_border_circle}' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 warning_turn_right:
   category: 'warning'
   name: 'turn right'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'turn-90-r', value: 'black' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+    { type: 'turn-90-l', value: 'black', transform: 'scale(-1,1)' }
   ]

 warning_turn_left:
   category: 'warning'
   name: 'turn left'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'turn-90-l', value: 'black' }
   ]

@@ -194,7 +189,8 @@
   category: 'warning'
   name: 'fire station'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'fire-station', value: 'black' }
   ]

@@ -202,15 +198,17 @@
   category: 'warning'
   name: 'bicycles'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'bicycle fit', value: 'black' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+    { type: 'bicycle', value: 'black', transform: '{fit_diamond}' }
   ]

 warning_dead_end:
   category: 'warning'
   name: 'dead end'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'dead-end', value: 'black' }
   ]

@@ -218,32 +216,17 @@
   category: 'warning'
   name: 'light rail crossing'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'light-rail', value: 'black' }
   ]

-
-warning_curve_reverse_right:
-  category: 'warning'
-  name: 'curve reverse right'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'curve-r-r', value: 'black' }
-  ]
-
-warning_curve_reverse_left:
-  category: 'warning'
-  name: 'curve reverse left'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'curve-r-l', value: 'black' }
-  ]
-
 warning_horizontal_alignment_left:
   category: 'warning'
   name: 'horizontal alignment left'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'h-align-l', value: 'black' }
   ]

@@ -251,15 +234,17 @@
   category: 'warning'
   name: 'horizontal alignment right'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'h-align-r', value: 'black' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+    { type: 'h-align-l', value: 'black', transform: 'scale(-1,1)' }
   ]

 warning_highway_divided:
   category: 'warning'
   name: 'highway divided'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'highway-divided', value: 'black' }
   ]

@@ -267,7 +252,8 @@
   category: 'warning'
   name: 'steep hill'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'steep-hill', value: 'black' }
   ]

@@ -275,7 +261,8 @@
   category: 'warning'
   name: 'low clearance'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'low-clearance', value: 'black' }
   ]

@@ -283,7 +270,8 @@
   category: 'warning'
   name: 'offset roads'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'offset-roads', value: 'black' }
   ]

@@ -291,7 +279,8 @@
   category: 'warning'
   name: 'slippery'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'slippery', value: 'black' }
   ]

@@ -302,14 +291,15 @@
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
     { type: 'no-l-or-u-turn', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 warning_winding_road_left:
   category: 'warning'
   name: 'winding road'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'winding-road-left', value: 'black' }
   ]

@@ -317,15 +307,17 @@
   category: 'warning'
   name: 'winding road'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'winding-road-right', value: 'black' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+    { type: 'winding-road-left', value: 'black', transform: 'scale(-1,1)' }
   ]

 warning_metric_clearance:
   category: 'warning'
   name: 'metric clearance'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'metric-clearance', value: 'black' }
   ]

@@ -333,7 +325,8 @@
   category: 'warning'
   name: 'intersection circular'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'roundabout', value: 'black' }
   ]

@@ -341,15 +334,17 @@
   category: 'warning'
   name: 'turn reverse right'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'turn-reverse-right', value: 'black' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+    { type: 'turn-reverse-left', value: 'black', transform: 'scale(-1,1)' }
   ]

 warning_turn_reverse_left:
   category: 'warning'
   name: 'turn reverse left'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'turn-reverse-left', value: 'black' }
   ]

@@ -357,7 +352,8 @@
   category: 'warning'
   name: 'side road acute angle right'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'side-road-a-a-r', value: 'black' }
   ]

@@ -365,7 +361,8 @@
   category: 'warning'
   name: 'side road acute angle left'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'side-road-a-a-l', value: 'black' }
   ]

@@ -373,7 +370,8 @@
   category: 'warning'
   name: 't roads'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 't-roads', value: 'black' }
   ]

@@ -384,14 +382,15 @@
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
     { type: 'hitch-hiking', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 warning_pass_left_or_right:
   category: 'warning'
   name: 'pass left or right'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'pass-l-r', value: 'black' }
   ]

@@ -399,7 +398,8 @@
   category: 'warning'
   name: 'share roads'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'share-roads', value: 'black' }
   ]

@@ -407,7 +407,8 @@
   category: 'warning'
   name: 'bicycle slippery'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'bicycle-slippery', value: 'black' }
   ]

@@ -418,14 +419,15 @@
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
     { type: 'pedestrian', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 warning_workers_in_road_ahead:
   category: 'warning'
   name: 'workers in road ahead'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'roadworks', value: 'black' }
   ]

@@ -433,7 +435,8 @@
   category: 'warning'
   name: 'play ground'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'play-ground', value: 'black' }
   ]

@@ -441,7 +444,8 @@
   category: 'warning'
   name: 'falling rocks'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'falling-rocks', value: 'black' }
   ]

@@ -449,7 +453,8 @@
   category: 'warning'
   name: 'hairpin curve'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'hairpin-curve', value: 'black' }
   ]

@@ -457,7 +462,8 @@
   category: 'warning'
   name: 'end'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'end', value: 'black' }
   ]

@@ -465,7 +471,8 @@
   category: 'warning'
   name: 'loop 270 degree'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'loop-270', value: 'black' }
   ]

@@ -473,7 +480,8 @@
   category: 'warning'
   name: 'y roads'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'y-roads', value: 'black' }
   ]

@@ -483,15 +491,16 @@
   elements: [
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
-    { type: 'arrow-straight', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'US-arrow-up', value: 'black' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 warning_added_lane_from_entering_roadway:
   category: 'warning'
   name: 'added lane from entering roadway'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'added-lane-entering-roadway', value: 'black' }
   ]

@@ -499,7 +508,8 @@
   category: 'warning'
   name: 'flaggers in road ahead'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'flaggers', value: 'black' }
   ]

@@ -507,7 +517,8 @@
   category: 'warning'
   name: 'skewed railroads crossing'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'skewed-railroads', value: 'black' }
   ]

@@ -515,7 +526,8 @@
   category: 'warning'
   name: 'trucks rollover'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'trucks-rollover', value: 'black' }
   ]

@@ -523,7 +535,8 @@
   category: 'warning'
   name: 'lightground railroad crossing'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'lightground-railroad-crossing', value: 'black' }
   ]

@@ -543,14 +556,15 @@
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
     { type: 'lorry', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 warning_motorcycle_crossing:
   category: 'warning'
   name: 'motorcycle crossing'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'motorbike', value: 'black' }
   ]

@@ -559,7 +573,8 @@
   name: 'railroad'
   elements: [
     { type: 'circle-bg', value: 'yellow' }
-    { type: 'circle-x', value: 'black' }
+    { type: 'circle-bar-rounded', value: 'black', transform: 'rotate(-45deg)' }
+    { type: 'circle-bar-rounded', value: 'black', transform: 'rotate(45deg)' }
     { type: 'railroad', value: 'black' }
   ]

@@ -569,7 +584,7 @@
   elements: [
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
-    { type: 'hazardous-material fit', value: 'black' }
+    { type: 'hazardous-material', value: 'black', transform: '{fit_border_circle}' }
     { type: 'circle-o', value: 'red' }
   ]

@@ -577,33 +592,27 @@
   category: 'warning'
   name: 'truck rollover with speed'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'truck-rollover-speed', value: 'black' }
   ]

-warning_turn_curve_with_speed:
-  category: 'warning'
-  name: 'turn curve with speed'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'turn-curve-w-speed', value: 'black' }
-  ]
-
 regulatory_no_rollerblading:
   category: 'regulatory'
   name: 'no rollerblading'
   elements: [
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
-    { type: 'rollerblading fit', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'rollerblading', value: 'black', transform: '{fit_border_circle}' }
+    { type: 'circle-bar-rounded', value: 'red', transform: 'rotate(-45deg)' }
   ]

 warning_triple_2_traverse_curve:
   category: 'warning'
   name: 'triple 2 traverse curve'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 't-2-traverse-curve', value: 'black' }
   ]

@@ -611,45 +620,36 @@
   category: 'warning'
   name: 'double reverse curve'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'double-reverse-curve', value: 'black' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+    { type: 'single-2-reverse-curve', value: 'black', transform: '{fit_diamond} translate(-9%)' }
+    { type: 'single-2-reverse-curve', value: 'black', transform: '{fit_diamond} translate(9%)' }
   ]

 warning_triple_2_traverse_curve:
   category: 'warning'
   name: 'triple 2 traverse curve'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 't-2-traverse-curve', value: 'black' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+    { type: 'single-2-reverse-curve', value: 'black', transform: '{fit_diamond} translate(-18%)' }
+    { type: 'single-2-reverse-curve', value: 'black', transform: '{fit_diamond}' }
+    { type: 'single-2-reverse-curve', value: 'black', transform: '{fit_diamond} translate(18%)' }
   ]

 warning_single_2_reverse_curve:
   category: 'warning'
   name: 'single 2 reverse curve'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
     { type: 'single-2-reverse-curve', value: 'black' }
   ]

-warning_curve_turn_left:
-  category: 'warning'
-  name: 'curve turn left'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'curve-r-l fit', value: 'black' }
-  ]
-
-warning_curve_turn_right:
-  category: 'warning'
-  name: 'curve turn right'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'curve-r-r fit', value: 'black' }
-  ]
-
 warning_side_road_perpendicular:
   category: 'warning'
   name: 'side road perpendicular'
   elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-  ]
+    { type: 'diamond-bg', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow', transform: 'scale(.95)' }
+  ]


move resizeGutter() call after dropletElement height is set

--- src/controller.coffee
+++ src/controller.coffee
@@ -330,11 +330,12 @@

     resizeBlockMode: ->
       @resizeTextMode()
-      @resizeGutter()

       @dropletElement.style.left = "#{@paletteElement.offsetWidth}px"
       @dropletElement.style.height = "#{@wrapperElement.offsetHeight}px"
       @dropletElement.style.width ="#{@wrapperElement.offsetWidth - @paletteWrapper.offsetWidth}px"
+
+      @resizeGutter()

       @mainCanvas.height = @dropletElement.offsetHeight
       @mainCanvas.width = @dropletElement.offsetWidth - @gutter.offsetWidth


add missing res close listener

add missing res close listener

--- src/controller.coffee
+++ src/controller.coffee
@@ -158,6 +158,7 @@
             stream = @model.getFile id, name, (err) -> next err if err
             stream.pipefilter = copySafeHeaders
             req.on 'close', -> stream.abort()
+            res.on 'close', -> stream.abort()
             stream.pipe res

     # Public: express handler to send a file
@@ -177,8 +178,8 @@
             stream = @model.getBinary id, name, (err) -> next err if err
             stream.pipefilter = copySafeHeaders
             req.on 'close', -> stream.abort()
+            res.on 'close', -> stream.abort()
             stream.pipe res

-
 module.exports = Controller


Fix focus on activating reply box

Fix focus on activating reply box

--- resources/assets/coffee/_classes/forum-topic-reply.coffee
+++ resources/assets/coffee/_classes/forum-topic-reply.coffee
@@ -76,7 +76,7 @@

     @enableFlash() if @getState('sticking') != '1' && currentUser.id?

-    @input[0].focus()
+    Timeout.set 0, => @input[0].focus()

   activateWithReply: (e, data) =>


localhost

localhost

--- src/db_connect.coffee
+++ src/db_connect.coffee
@@ -5,7 +5,7 @@
     assert = require('assert')

     # // Connection URL
-    url = 'mongodb://163.47.16.20:27017/test'
+    url = 'mongodb://localhost:27017/test'
      # Use connect method to connect to the Server
     MongoClient.connect(url, (err, db)->
       assert.equal(null, err)


Resolve CONFIG_DIR to absolute path

Resolve CONFIG_DIR to absolute path

--- lib/config.coffee
+++ lib/config.coffee
@@ -19,7 +19,7 @@
 common = require './common'

 options = {
-  CONFIG_DIR : {type : 'string', default : 'config'},
+  CONFIG_DIR : {type : 'path', default : 'config'},
   MONGODB_CONNECTION_URL : {type : 'string', default : 'mongodb://127.0.0.1/genieacs'},
   REDIS_PORT : {type : 'int', default : 6379},
   REDIS_HOST : {type : 'string', default : '127.0.0.1'},
@@ -80,6 +80,8 @@
         String(val).trim().toLowerCase() in ['true', 'on', 'yes', '1']
       when 'string'
         String(val)
+      when 'path'
+        path.resolve(val)
       else
         null

@@ -126,14 +128,8 @@
   setConfig(k, v)

-# Find config dir
-if exports.argv['--config-dir']?
-  allConfig.CONFIG_DIR = exports.argv['--config-dir']
-else if process.env['GENIEACS_CONFIG_DIR']?
-  allConfig.CONFIG_DIR = process.env['GENIEACS_CONFIG_DIR']
-else
-  allConfig.CONFIG_DIR = options.CONFIG_DIR.default
-
+# Use default config dir if none defined
+setConfig('CONFIG_DIR', options['CONFIG_DIR'].default)

 # Configuration file
 for k, v of require(path.resolve(allConfig.CONFIG_DIR, 'config'))


Incorrect touchstop event type. Renaming to touchend

--- lib/assets/javascripts/zui53/tools/pan_tool.js.coffee
+++ lib/assets/javascripts/zui53/tools/pan_tool.js.coffee
@@ -43,7 +43,7 @@
       window.removeEventListener 'mouseup', @stop, true

       window.removeEventListener 'touchmove', @pan, true
-      window.removeEventListener 'touchstop', @stop, true
+      window.removeEventListener 'touchend', @stop, true

       @stopEvent(e)

@@ -51,7 +51,7 @@
       # console.log "start panning (touch)"
       @_start_with(e.touches[0].clientX, e.touches[0].clientY)
       @eventDispatcher.addEventListener 'touchmove', @touch_move, true
-      @eventDispatcher.addEventListener 'touchstop', @touch_stop, true
+      @eventDispatcher.addEventListener 'touchend', @touch_stop, true
       e.preventDefault()

     touch_move: (e)=>
@@ -59,7 +59,7 @@

     touch_stop: (e)=>
       @eventDispatcher.removeEventListener 'touchmove', @touch_move, true
-      @eventDispatcher.removeEventListener 'touchstop', @touch_stop, true
+      @eventDispatcher.removeEventListener 'touchend', @touch_stop, true

     _pan_with: (x, y)=>
       # console.log "panning PAN Tool"


Log a warning when require.resolve cannot find the file

--- src/stdlib/require.coffee
+++ src/stdlib/require.coffee
@@ -57,7 +57,9 @@
   coffee: (file) ->
     exts.js(file, __coffeeCache(file))

-resolve = (file) ->
+resolve = (name, {verifyExistence}={}) ->
+  verifyExistence ?= true
+  file = name
   if /!/.test file
     parts = file.split '!'
     file = parts[parts.length-1]
@@ -75,18 +77,19 @@
       fileExists = /\.(.+)$/.test(file) and __exists "#{path}/#{file}"
       jsFileExists = not /\.(.+)$/.test(file) and __exists "#{path}/#{file}.js"

-      if fileExists
-        file = "#{path}/#{file}"
       if jsFileExists
         file = "#{path}/#{file}.js"
+      else if fileExists
+        file = "#{path}/#{file}"
       else if expanded = __expand "#{path}/#{file}"
         file = expanded
   else
     file = __expand(file) or file

-  if file[0] == '/'
+  if file[0] == '/' and (not verifyExistence or __exists(file))
     file
   else
+    console.warn("Failed to resolve '#{name}'")
     null

 __expand = (path) ->


implementing crossdomain requests

implementing crossdomain requests

--- src/sdk.coffee
+++ src/sdk.coffee
@@ -37,7 +37,7 @@
         client_id:      options.client_id
         redirect_uri:   options.redirect_uri
         response_type:  "code_and_token"
-        scope:          options.scope || ""
+        scope:          options.scope || "non-expiring"
         display:        "popup"
       SC._popupWindow = SC.Helper.openCenteredPopup uri.toString(), 456, 510
     else
@@ -111,17 +111,53 @@
       if !sound = soundManager.getSoundById(options.id)
         sound = soundManager.createSound(options)
       sound
-
-############################
-#  NETWORKING              #
-############################
-  get: (path, query, callback) ->
-    uri = this.prepareRequestURI(path, query)
-    unless callback?
+
+############################
+#   XDM post, put, delete  #
+############################
+
+  whenXDMReady: (callback) ->
+    if window.crossdomain? #this.apiXDChannel?
+      callback()
+    else
+      SC.Helper.loadJavascript "http://" + this.hostname("connect") + "/crossdomain-requests-js/crossdomain-ajax.js", ->
+        callback()
+
+  request: (method, path, query, callback) ->
+    if !callback?
       callback = query
       query = undefined
-    SC.Helper.JSONP.get uri, callback
-
+    query ||= {}
+    uri = SC.prepareRequestURI(path, query)
+    uri.query.format = "json"
+    #data = uri.encodeParams(uri.query) #uri.query = {}
+
+    this.whenXDMReady =>
+      crossdomain.ajax({
+        type: method
+        url:  uri.toString()
+        #data: data
+        headers:
+          "Content-Type": "application/x-www-form-urlencoded"
+        error: (response) ->
+          obj = JSON.parse(response)
+          callback(obj)
+        success: (response) ->
+          obj = JSON.parse(response)
+          callback(obj)
+      })
+
+  post:   (path, query, callback) ->
+    this.request("POST",   path, query, callback)
+
+  put:    (path, query, callback) ->
+    this.request("PUT",    path, query, callback)
+
+  get:    (path, query, callback) ->
+    this.request("GET",    path, query, callback)
+
+  delete: (path, callback) ->
+    this.request("DELETE", path, {}, callback)

   prepareRequestURI: (path, query={}) ->
     uri = new SC.URI(path, {"decodeQuery": true})


add some sweet docs

add some sweet docs

--- _source/packages/newspring:core/server/lib/apollos/give.coffee
+++ _source/packages/newspring:core/server/lib/apollos/give.coffee
@@ -1,3 +1,15 @@
+###
+
+  isAccountType
+
+  @example check to see if schema is of a certain AccountType
+
+    isAccountType(schema, type)
+
+  @param schema [SimpleSchema] generally passed as @ or this
+  @param type [String] the type of account compared to the schema's AccountType
+
+###
 isAccountType = (schema, type) ->
   isCredit = schema.field('AccountType').value == type
   if isCredit and !schema.isSet and (!schema.operator or schemavalue == null or schema.value == '')
@@ -71,7 +83,7 @@

   Apollos.giveTransaction

-  @example validate and pass transaction data to Rcok
+  @example validate and pass transaction data to Rock

     Apollos.giveTransation(data)