UNPKG

6.09 kBtext/coffeescriptView Raw
1_ = require("underscore")
2cliff = require("cliff")
3degrees = require("upon").degrees
4Ensemble = require("lin").Ensemble
5
6# This is just points presentation,
7# It could later be done with a `Backbone.View`.
8
9module.exports = phase = (streamin, stream) ->
10 streamin.on "data", (data) ->
11 json = JSON.parse(data)
12
13 # It's just about output format from here on.
14 if json.length > 0
15 ensemble = new Ensemble
16 longitude = " longitude" # the name cliff label
17 rpad = ' ' # right-padding for better readability
18 table =
19 [ { "key": " "
20 , "req": ["id", "sid"]
21 , "act": true
22 , "val": (its, it) ->
23 lead = if its.sid >= 10000 then "+" else ""
24 if it.get('u')? then it.get('u').white else lead
25 }
26 , { "key": "what"
27 , "req": ["id"]
28 , "act": true
29 , "val": (its, it) ->
30 if it.get('id') is '?' then its.id else it.get 'name'
31 }
32 , { "key": longitude
33 , "req": ["lon"]
34 , "act": true
35 , "val": (its) ->
36 degrees.lon(its.lon).rep('str')
37 , sort: "lon"
38 }
39 , { "key": "~"
40 , "req": ["day_lon"]
41 , "act": true
42 , "val": (its) ->
43 if its.day_lon < 0 then '℞'.red else ''
44 }
45 , { "key": " speed"
46 , "req": ["day_lon"]
47 , "act": true
48 , "val": (its) ->
49 if its.day_lon?
50 front = ('' if its.day_lon < 0 or its.day_lon >= 10) ? ' '
51 front + its.day_lon.toFixed 3
52 else ''
53 }
54 , { "key": " latitude"
55 , "req": ["lat"]
56 , "act": false
57 , "val": (its) ->
58 degrees.of(its.lat).str()
59 }
60 , { "key": "distance"
61 , "req": ["dau"]
62 , "act": true
63 , "val": (its) ->
64 return '' unless _.isNumber its.dau
65 its.dau.toFixed(4 - String(Math.floor its.dau).length) + " AU"
66 }
67 , { "key": "reason"
68 , "req": ["re"]
69 , "act": true
70 , "val": (its) ->
71 its.re
72 }
73 ]
74
75 # Reconsider what will be shown.
76 show = []
77 for item in table
78 # Don't show inactive stuff.
79 continue if item.act isnt true
80 # Don't work with columns all of whose values are entirely the same.
81 continue if 1 is _.size _.uniq _.pluck json, item.req[0]
82 show.push item
83 table = show
84
85 # The out-values, titles and their color.
86 out = []
87 titles = _.pluck table, 'key'
88 color = []
89 color.push "white" for count in [0..table.length]
90
91 # Add the representations for better readability.
92 lon = degrees.lon 0 # just for representation symbols
93 for i in [0..11]
94 json.push
95 marker: true
96 id: lon.representations[i]
97 lon: i * 30
98 re: "zodiac".green
99
100 # Process and sort.
101 for i, item of json
102 out.push { order: [] }
103 for col in table
104 it = ensemble.id item.id
105 piece = col.val item, it
106 piece += rpad if col.key isnt '~'
107 out[i][col.key] = piece
108 if col.sort? and not item.marker
109 out[i].order.push Number(item[col.sort])
110 out[i].id = item.id # for post-processing
111 # Output markers for each representation.
112 if item.marker is true
113 # TODO: append `" topical % fortune"` house numbers to `what`.
114 what = out[i]['what']
115 mark = "#{item.lon}\u00B0"
116 mark = ' ' + mark for count in [0..(5 - mark.length)]
117 out[i].marker = true
118 out[i].order.push Number(item.lon)
119 out[i]['what'] = what.green
120 out[i][longitude] = mark.green
121 out = _.sortBy out, (obj) -> obj['order'][0]
122
123 # TODO: an ugly hack - resolve this technical debt!
124 # It all comes from lon 0 being 360. Perhaps a 2nd
125 # special kind of longitude should be further sub-classed?
126 for idx in [(out.length-1)..0]
127 if out[idx].order[0] is 360 then out[idx].order[0] = 0 else break
128 # Sort again, because of the above...
129 out = _.sortBy out, (obj) -> obj['order'][0]
130
131 # Reduce and write to the stream.
132 [seq, prev] = [{}, {}]
133 for i, item of out
134 out[i].extra = false # innocent by default (i.e. not guilty)
135 # Instead of `if prev[longitude] isnt item[longitude]`.
136 # Note: would be nice if we didn't hardcode `order[0]`
137 # to be longitude for sure (technical debt).
138 # It is used all over the place!
139 if prev.order?[0] isnt item.order[0]
140 if _.size(seq) > 1
141 angled = topical = fortune = false
142 # One or more of the angles can be found in this sequence.
143 if (_.union ['AS', 'MC', 'DS', 'IC'], _.keys seq).length >= 1
144 angled = true
145 for id, idx of seq
146 # Makes any house extra.
147 out[idx].extra = true if id[0] is 'H' and angled is true
148 # Topical & Fortune Houses.
149 if id[0] is 'T' or id[0] is 'F'
150 out[idx].extra = true
151 switch id[0]
152 when 'T' then topical = id.substr 1
153 when 'F' then fortune = id.substr 1
154 if topical isnt false
155 out[i_mark].what += " #{topical}".white
156 if fortune isnt false
157 out[i_mark].what += " / #{fortune}".white
158 # Reset the sequence after a longitude change is processed.
159 seq = {}
160 # From here on, there is always at least one one id in the sequence.
161 seq["#{item.id}"] = i
162 # It's mportant to set the marker index after processing.
163 # Otherwise, sometimes the next marker steals the topics.
164 i_mark = i if item.marker is true
165 prev = item
166 outer = _.filter out, (final) -> final.extra is false
167 stream.write cliff.stringifyObjectRows outer, titles, color
168
169 else stream.write "Given no data."
170
171 stream.emit "end"