vines-services 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/vines/services/command/init.rb +10 -7
- data/lib/vines/services/connection.rb +5 -0
- data/lib/vines/services/storage/couchdb/service.rb +7 -0
- data/lib/vines/services/version.rb +1 -1
- data/web/coffeescripts/services.coffee +15 -6
- data/web/coffeescripts/systems.coffee +51 -11
- data/web/javascripts/app.js +2 -2
- data/web/javascripts/services.js +23 -18
- data/web/javascripts/systems.js +65 -16
- data/web/stylesheets/app.css +63 -39
- data/web/stylesheets/common.css +7 -1
- data/web/stylesheets/systems.css +55 -38
- metadata +20 -20
@@ -26,7 +26,7 @@ module Vines
|
|
26
26
|
Dir.chdir(dir) { send("init_#{sub}") }
|
27
27
|
end
|
28
28
|
puts "Initialized server, agent, and services directories: #{@domain}"
|
29
|
-
puts "Login at http://localhost:5280/"
|
29
|
+
puts "Login as #{user.jid} at http://localhost:5280/"
|
30
30
|
EM.stop
|
31
31
|
end.resume
|
32
32
|
end
|
@@ -88,9 +88,9 @@ module Vines
|
|
88
88
|
until create_db(host, port, db)
|
89
89
|
puts "CouchDB connection failed"
|
90
90
|
$stdout.write('CouchDB Host: ')
|
91
|
-
host = $stdin.gets.
|
91
|
+
host = $stdin.gets.strip
|
92
92
|
$stdout.write('CouchDB Port: ')
|
93
|
-
port = $stdin.gets.
|
93
|
+
port = $stdin.gets.strip
|
94
94
|
end
|
95
95
|
{host: host, port: port, name: db}
|
96
96
|
end
|
@@ -119,10 +119,11 @@ module Vines
|
|
119
119
|
end
|
120
120
|
|
121
121
|
def ask_for_jid
|
122
|
+
puts "Creating a new chat user account"
|
122
123
|
jid = nil
|
123
124
|
until jid
|
124
|
-
$stdout.write('
|
125
|
-
if node = $stdin.gets.
|
125
|
+
$stdout.write('User ID: ')
|
126
|
+
if node = $stdin.gets.strip.split('@').first
|
126
127
|
jid = Vines::JID.new(node, @domain) rescue nil
|
127
128
|
end
|
128
129
|
end
|
@@ -130,14 +131,16 @@ module Vines
|
|
130
131
|
end
|
131
132
|
|
132
133
|
def ask_for_password
|
134
|
+
at_exit { `stty echo` }
|
133
135
|
password = nil
|
134
136
|
until password
|
135
137
|
$stdout.write('Password: ')
|
136
138
|
`stty -echo`
|
137
|
-
password = $stdin.gets.
|
138
|
-
password = nil if password.empty?
|
139
|
+
password = $stdin.gets.strip
|
140
|
+
password = nil if password.empty? || password.length < 8
|
139
141
|
`stty echo`
|
140
142
|
puts
|
143
|
+
puts 'Must be at least 8 characters' unless password
|
141
144
|
end
|
142
145
|
password
|
143
146
|
end
|
@@ -18,6 +18,11 @@ module Vines
|
|
18
18
|
@throttle = Throttle.new(@stream)
|
19
19
|
@queues = {}
|
20
20
|
|
21
|
+
@stream.register_handler(:stream_error) do |e|
|
22
|
+
log.error(e.message)
|
23
|
+
true # prevent EM.stop
|
24
|
+
end
|
25
|
+
|
21
26
|
@stream.register_handler(:disconnected) do
|
22
27
|
log.info("Stream disconnected, reconnecting . . .")
|
23
28
|
EM::Timer.new(10) do
|
@@ -29,6 +29,7 @@ module Vines
|
|
29
29
|
validates_uniqueness_of :jid
|
30
30
|
validates_presence_of :jid
|
31
31
|
validate :compile_view
|
32
|
+
validate :presence_of_account
|
32
33
|
|
33
34
|
design do
|
34
35
|
view :by_name,
|
@@ -155,6 +156,12 @@ module Vines
|
|
155
156
|
errors.add(:base, e.message)
|
156
157
|
end
|
157
158
|
|
159
|
+
def presence_of_account
|
160
|
+
accounts.map! {|a| a.strip }.reject! {|a| a.empty? }
|
161
|
+
accounts.sort!.uniq!
|
162
|
+
errors.add(:base, 'At least one user account is required.') if accounts.empty?
|
163
|
+
end
|
164
|
+
|
158
165
|
def update_views
|
159
166
|
js = VQL::Compiler.new.to_full_js(self.class.by_name.to_a)
|
160
167
|
design = database.get(VIEW_ID) rescue nil
|
@@ -116,7 +116,7 @@ class ServicesPage
|
|
116
116
|
|
117
117
|
# only validate if text changed
|
118
118
|
prev = $('#syntax').data 'prev'
|
119
|
-
code =
|
119
|
+
code = $('#syntax').val().trim()
|
120
120
|
$('#syntax').data 'prev', code
|
121
121
|
return unless code && code != prev
|
122
122
|
|
@@ -131,24 +131,31 @@ class ServicesPage
|
|
131
131
|
|
132
132
|
validateForm: ->
|
133
133
|
$('#name-error').empty()
|
134
|
+
$('#unix-users-error').empty()
|
134
135
|
valid = true
|
135
136
|
|
136
|
-
name =
|
137
|
+
name = $('#name').val().trim()
|
137
138
|
if name == ''
|
138
139
|
$('#name-error').text 'Name is required.'
|
139
140
|
valid = false
|
140
141
|
|
142
|
+
if this.accounts().length == 0
|
143
|
+
$('#unix-users-error').text 'At least one user account is required.'
|
144
|
+
valid = false
|
145
|
+
|
141
146
|
valid
|
142
147
|
|
148
|
+
accounts: ->
|
149
|
+
accounts = $('#unix-users').val().split(',')
|
150
|
+
(u.trim() for u in accounts when u.trim().length > 0)
|
151
|
+
|
143
152
|
save: ->
|
144
|
-
return unless this.validateForm()
|
153
|
+
return false unless this.validateForm()
|
145
154
|
users = $('#users :checked').map(-> $(this).val()).get()
|
146
|
-
accounts = $('#unix-users').val().split(',')
|
147
|
-
accounts = ($.trim u for u in accounts when $.trim(u).length > 0)
|
148
155
|
service =
|
149
156
|
name: $('#name').val()
|
150
157
|
code: $('#syntax').val()
|
151
|
-
accounts: accounts
|
158
|
+
accounts: this.accounts()
|
152
159
|
users: users
|
153
160
|
service['id'] = $('#id').val() if $('#id').val().length > 0
|
154
161
|
|
@@ -292,6 +299,8 @@ class ServicesPage
|
|
292
299
|
<ul id="users" class="scroll"></ul>
|
293
300
|
<label for="unix-users">Unix Accounts</label>
|
294
301
|
<input id="unix-users" type="text"/>
|
302
|
+
<p id="unix-users-error" class="error"></p>
|
303
|
+
<p class="hint">Comma separated user names like: apache, postgres, root, etc.</p>
|
295
304
|
</fieldset>
|
296
305
|
</section>
|
297
306
|
</div>
|
@@ -41,6 +41,7 @@ class SystemsPage
|
|
41
41
|
for contact in contacts
|
42
42
|
option = $("""
|
43
43
|
<li data-jid="#{contact.jid}">
|
44
|
+
<span class="icon"></span>
|
44
45
|
<span class="text"></span>
|
45
46
|
<span class="unread" style="display:none;"></span>
|
46
47
|
</li>
|
@@ -51,6 +52,17 @@ class SystemsPage
|
|
51
52
|
option.attr 'data-name', name
|
52
53
|
option.attr 'data-group', group
|
53
54
|
$('.text', option).text name
|
55
|
+
opts =
|
56
|
+
fill: '#fff'
|
57
|
+
stroke: '#404040'
|
58
|
+
'stroke-width': 0.3
|
59
|
+
opacity: 1.0
|
60
|
+
scale: 0.65
|
61
|
+
icon = switch group
|
62
|
+
when 'People' then ICONS.man
|
63
|
+
when 'Services' then ICONS.magic
|
64
|
+
else ICONS.run
|
65
|
+
new Button $('.icon', option), icon, opts
|
54
66
|
|
55
67
|
message: (message) ->
|
56
68
|
this.queueMessage message
|
@@ -60,7 +72,7 @@ class SystemsPage
|
|
60
72
|
if me || from == @currentContact
|
61
73
|
bottom = this.atBottom()
|
62
74
|
this.appendMessage message
|
63
|
-
this.scroll({animate: true}) if bottom
|
75
|
+
this.scroll({animate: true}) if bottom || me
|
64
76
|
else
|
65
77
|
chat = this.chat message.from
|
66
78
|
chat.unread++
|
@@ -80,6 +92,7 @@ class SystemsPage
|
|
80
92
|
node = $("""<li data-jid="#{from}"><pre></pre></li>""").appendTo '#messages'
|
81
93
|
prefix = if me then '$ ' else ''
|
82
94
|
$('pre', node).text prefix + message.text
|
95
|
+
$('#message-form').css 'top', '0px'
|
83
96
|
unless me
|
84
97
|
node.append("""
|
85
98
|
<footer>
|
@@ -121,6 +134,7 @@ class SystemsPage
|
|
121
134
|
selectContact: (event) ->
|
122
135
|
$('#blank-slate').fadeOut(200, -> $(this).remove())
|
123
136
|
$('#roster').hide()
|
137
|
+
$('#message').focus()
|
124
138
|
|
125
139
|
selected = $(event.currentTarget)
|
126
140
|
jid = selected.attr 'data-jid'
|
@@ -130,7 +144,7 @@ class SystemsPage
|
|
130
144
|
|
131
145
|
$('#message-label').text $('.text', selected).text()
|
132
146
|
$('#messages').empty()
|
133
|
-
$('#message').
|
147
|
+
$('#message-form').css 'top', '10px'
|
134
148
|
@layout.resize()
|
135
149
|
this.restoreChat(jid)
|
136
150
|
|
@@ -175,6 +189,27 @@ class SystemsPage
|
|
175
189
|
input.val ''
|
176
190
|
false
|
177
191
|
|
192
|
+
showRoster: ->
|
193
|
+
container = $ '#container'
|
194
|
+
form = $ '#message-form'
|
195
|
+
roster = $ '#roster'
|
196
|
+
items = $ '#roster-items'
|
197
|
+
rform = $ '#roster-form'
|
198
|
+
|
199
|
+
up = container.height() - form.position().top < container.height() / 2
|
200
|
+
if up
|
201
|
+
roster.css 'top', ''
|
202
|
+
roster.css 'bottom', (form.outerHeight() + 5) + 'px'
|
203
|
+
height = container.height() - form.outerHeight() - 20
|
204
|
+
else
|
205
|
+
roster.css 'bottom', ''
|
206
|
+
roster.css 'top', (form.position().top + form.outerHeight()) + 'px'
|
207
|
+
height = container.height() - form.position().top - 30
|
208
|
+
|
209
|
+
items.css 'max-height', (height - rform.outerHeight() - 40) + 'px'
|
210
|
+
roster.css 'max-height', height + 'px'
|
211
|
+
roster.show()
|
212
|
+
|
178
213
|
drawBlankSlate: ->
|
179
214
|
$("""
|
180
215
|
<form id="blank-slate" class="float">
|
@@ -187,7 +222,7 @@ class SystemsPage
|
|
187
222
|
</form>
|
188
223
|
""").appendTo '#alpha'
|
189
224
|
$('#blank-slate').submit =>
|
190
|
-
|
225
|
+
this.showRoster()
|
191
226
|
@layout.resize()
|
192
227
|
false
|
193
228
|
|
@@ -200,7 +235,7 @@ class SystemsPage
|
|
200
235
|
$('#container').hide().empty()
|
201
236
|
$("""
|
202
237
|
<div id="alpha" class="primary column x-fill y-fill">
|
203
|
-
<ul id="messages" class="scroll
|
238
|
+
<ul id="messages" class="scroll"></ul>
|
204
239
|
<form id="message-form">
|
205
240
|
<label id="message-label"></label>
|
206
241
|
<input id="message" name="message" type="text" maxlength="1024" placeholder="Type a command and press enter to send"/>
|
@@ -211,13 +246,21 @@ class SystemsPage
|
|
211
246
|
</div>
|
212
247
|
</div>
|
213
248
|
""").appendTo '#container'
|
249
|
+
# padding is removed when first message is received
|
250
|
+
$('#message-form').css 'top', '10px'
|
214
251
|
$('#message-form').submit => this.send()
|
215
252
|
$('#messages').click -> $('#roster').hide()
|
216
253
|
$('#message').focus -> $('#roster').hide()
|
254
|
+
$(document).keyup (e) ->
|
255
|
+
$('#roster').hide() if e.keyCode == 27 # escape
|
217
256
|
|
218
257
|
this.roster()
|
219
258
|
$('#message-label').click =>
|
220
|
-
$('#roster')
|
259
|
+
roster = $('#roster')
|
260
|
+
if roster.is(':visible')
|
261
|
+
roster.hide()
|
262
|
+
else
|
263
|
+
this.showRoster()
|
221
264
|
|
222
265
|
$('#message').keyup (e) =>
|
223
266
|
switch e.keyCode # up, down keys trigger history
|
@@ -236,6 +279,7 @@ class SystemsPage
|
|
236
279
|
$('#container').show()
|
237
280
|
@layout = this.resize()
|
238
281
|
this.scroll()
|
282
|
+
$('#message').focus()
|
239
283
|
|
240
284
|
new Filter
|
241
285
|
list: '#roster-items'
|
@@ -245,14 +289,10 @@ class SystemsPage
|
|
245
289
|
|
246
290
|
resize: ->
|
247
291
|
container = $ '#container'
|
248
|
-
|
249
|
-
items = $ '#roster-items'
|
250
|
-
rform = $ '#roster-form'
|
292
|
+
msgs = $ '#messages'
|
251
293
|
msg = $ '#message'
|
252
294
|
form = $ '#message-form'
|
253
295
|
label = $ '#message-label'
|
254
296
|
new Layout ->
|
255
297
|
msg.width form.width() - label.width() - 32
|
256
|
-
height
|
257
|
-
roster.css 'max-height', height
|
258
|
-
items.css 'max-height', height - rform.outerHeight() - 10
|
298
|
+
msgs.css 'max-height', container.height() - form.height()
|
data/web/javascripts/app.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
var Api,__bind=function(a,b){return function(){return a.apply(b,arguments)}};Api=function(){function b(b){this.session=b,this.user=null,this.session.onRoster(__bind(function(){return this.get(a,{jid:this.session.bareJid()},__bind(function(a){return this.user=a},this))},this))}var a;return a="http://getvines.com/protocol/users",b.prototype.jid=function(){return"vines."+this.session.bareJid().split("@")[1]},b.prototype.get=function(a,b,c){var d,e,f;e=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="get">\n <query xmlns="'+a+'"/>\n</iq>');for(d in b)f=b[d],$("query",e).attr(d,f);return this.session.sendIQ(e,__bind(function(a){var b;b=$(a).attr("type")==="result";if(!b)return;return c(JSON.parse($("query",a).text()))},this))},b.prototype.get2=function(a,b,c){var d;return d=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="get">\n <query xmlns="'+a+'"/>\n</iq>'),$("query",d).text(b),this.session.sendIQ(d,__bind(function(a){var b;b=$(a).attr("type")==="result";if(!b)return;return c(JSON.parse($("query",a).text()))},this))},b.prototype.remove=function(a,b,c){var d;return d=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="set">\n <query xmlns="'+a+'" action="delete" id=""/>\n</iq>'),$("query",d).attr("id",b),this.session.sendIQ(d,c)},b.prototype.save=function(a,b,c){var d;return d=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="set">\n <query xmlns="'+a+'"/>\n</iq>'),$("query",d).text(JSON.stringify(b)),this.session.sendIQ(d,__bind(function(a){var b;b=$(a).attr("type")==="result";if(!b)return;return c(JSON.parse($("query",a).text()))},this))},b}();var Commands;Commands=function(){function a(){this.buf=[],this.index=0}return a.prototype.prev=function(){var a;return a=this.buf[--this.index],a||(this.index=-1),a||""},a.prototype.next=function(){var a;return a=this.buf[++this.index],a||(this.index=this.buf.length),a||""},a.prototype.push=function(a){return this.buf.push(a),this.index=this.buf.length},a}();var SystemsPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};SystemsPage=function(){function a(a){this.session=a,this.session.onRoster(__bind(function(){return this.roster()},this)),this.session.onMessage(__bind(function(a){return this.message(a)},this)),this.session.onPresence(__bind(function(a){return this.presence(a)},this)),this.commands=new Commands,this.chats={},this.currentContact=null,this.layout=null}return a.prototype.datef=function(a){var b,c,d,e;return b=new Date(a),d=b.getHours()<12?" am":" pm",c=b.getHours()>12?b.getHours()-12:b.getHours(),c===0&&(c=12),e=b.getMinutes()+"",e.length===1&&(e="0"+e),c+":"+e+d},a.prototype.groupContacts=function(){var a,b,c,d,e,f,g,h;c={},g=this.session.roster;for(d in g){a=g[d],h=a.groups;for(e=0,f=h.length;e<f;e++)b=h[e],(c[b]||(c[b]=[])).push(a)}return c},a.prototype.roster=function(){var a,b,c,d,e,f,g,h,i,j,k,l;d=this.groupContacts(),i=function(){var a;a=[];for(c in d)b=d[c],a.push(c);return a}(),i=i.sort(function(a,b){return a=a.toLowerCase(),b=b.toLowerCase(),a>b?1:a<b?-1:0}),e=$("#roster-items").empty(),l=[];for(j=0,k=i.length;j<k;j++)c=i[j],b=d[c],g=$('<li class="group"></li>').appendTo(e),g.text(c),g.attr("data-group",c),l.push(function(){var d,g,i;i=[];for(d=0,g=b.length;d<g;d++)a=b[d],h=$('<li data-jid="'+a.jid+'">\n <span class="text"></span>\n <span class="unread" style="display:none;"></span>\n</li>').appendTo(e),a.offline()&&h.addClass("offline"),h.click(__bind(function(a){return this.selectContact(a)},this)),f=a.name||a.jid.split("@")[0],h.attr("data-name",f),h.attr("data-group",c),i.push($(".text",h).text(f));return i}.call(this));return l},a.prototype.message=function(a){var b,c,d,e;this.queueMessage(a),e=a.from===this.session.jid(),d=a.from.split("/")[0];if(!e&&d!==this.currentContact)return c=this.chat(a.from),c.unread++,this.eachContact(d,function(a){return $(".unread",a).text(c.unread).show()});b=this.atBottom(),this.appendMessage(a);if(b)return this.scroll({animate:!0})},a.prototype.eachContact=function(a,b){var c,d,e,f,g;f=$("#roster-items li[data-jid='"+a+"']").get(),g=[];for(d=0,e=f.length;d<e;d++)c=f[d],g.push(b($(c)));return g},a.prototype.appendMessage=function(a){var b,c,d,e,f,g,h;d=a.from===this.session.jid(),h=$("jid",a.node).text(),c=(h||a.from).split("/")[0],b=this.session.roster[c],e=b?b.name||c:c,f=$('<li data-jid="'+c+'"><pre></pre></li>').appendTo("#messages"),g=d?"$ ":"",$("pre",f).text(g+a.text);if(!d)return f.append('<footer>\n <span class="author"></span> @\n <span class="time">'+this.datef(a.received)+"</span>\n</footer>"),$(".author",f).text(e)},a.prototype.queueMessage=function(a){var b,c,d;return d=a.from===this.session.jid(),c=a[d?"to":"from"],b=this.chat(c),b.jid=c,b.messages.push(a)},a.prototype.chat=function(a){var b,c;return b=a.split("/")[0],c=this.chats[b],c||(c={jid:a,messages:[],unread:0},this.chats[b]=c),c},a.prototype.presence=function(a){var b,c;c=a.from.split("/")[0];if(c===this.session.bareJid())return;if(!a.type||a.offline)b=this.session.roster[c],this.eachContact(c,function(a){return b.offline()?a.addClass("offline"):a.removeClass("offline")});if(a.offline)return this.chat(c).jid=c},a.prototype.selectContact=function(a){var b,c,d;$("#blank-slate").fadeOut(200,function(){return $(this).remove()}),$("#roster").hide(),d=$(a.currentTarget),c=d.attr("data-jid"),b=this.session.roster[c];if(this.currentContact===c)return;return this.currentContact=c,$("#message-label").text($(".text",d).text()),$("#messages").empty(),$("#message").focus(),this.layout.resize(),this.restoreChat(c)},a.prototype.restoreChat=function(a){var b,c,d,e,f;b=this.chats[a],c=[],b&&(c=b.messages,b.unread=0,this.eachContact(a,function(a){return $(".unread",a).text("").hide()}));for(e=0,f=c.length;e<f;e++)d=c[e],this.appendMessage(d);return this.scroll()},a.prototype.scroll=function(a){var b;return a||(a={}),b=$("#messages"),a.animate?b.animate({scrollTop:b.prop("scrollHeight")},400):b.scrollTop(b.prop("scrollHeight"))},a.prototype.atBottom=function(){var a,b;return b=$("#messages"),a=b.prop("scrollHeight")-b.outerHeight(),b.scrollTop()>=a},a.prototype.send=function(){var a,b,c,d;return this.currentContact?(b=$("#message"),d=b.val().trim(),d&&(a=this.chats[this.currentContact],c=a?a.jid:this.currentContact,this.message({from:this.session.jid(),text:d,to:c,received:new Date}),this.session.sendMessage(c,d),this.commands.push(d)),b.val(""),!1):!1},a.prototype.drawBlankSlate=function(){return $('<form id="blank-slate" class="float">\n <p>\n Services, and individual systems, can be controlled by sending\n them shell commands through this terminal. Select a system to chat with\n to get started.\n </p>\n <input type="submit" value="Select System"/>\n</form>').appendTo("#alpha"),$("#blank-slate").submit(__bind(function(){return $("#roster").show(),this.layout.resize(),!1},this))},a.prototype.draw=function(){var a,b;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","systems-page"),$("#container").hide().empty(),$('<div id="alpha" class="primary column x-fill y-fill">\n <ul id="messages" class="scroll y-fill"></ul>\n <form id="message-form">\n <label id="message-label"></label>\n <input id="message" name="message" type="text" maxlength="1024" placeholder="Type a command and press enter to send"/>\n </form>\n <div id="roster" class="float" style="display:none;">\n <ul id="roster-items"></ul>\n <div id="roster-form"></div>\n </div>\n</div>').appendTo("#container"),$("#message-form").submit(__bind(function(){return this.send()},this)),$("#messages").click(function(){return $("#roster").hide()}),$("#message").focus(function(){return $("#roster").hide()}),this.roster(),$("#message-label").click(__bind(function(){return $("#roster").toggle()},this)),$("#message").keyup(__bind(function(a){switch(a.keyCode){case 38:return $("#message").val(this.commands.prev());case 40:return $("#message").val(this.commands.next())}},this)),this.currentContact?(this.currentContact&&this.restoreChat(this.currentContact),a=this.session.roster[this.currentContact],b=a.name||a.jid.split("@")[0],$("#message-label").text(b),$("#message").focus()):this.drawBlankSlate(),$("#container").show(),this.layout=this.resize(),this.scroll(),new Filter({list:"#roster-items",form:"#roster-form",attrs:["data-jid","data-name"]}),$("form","#roster-form").show()},a.prototype.resize=function(){var a,b,c,d,e,f,g;return a=$("#container"),g=$("#roster"),c=$("#roster-items"),f=$("#roster-form"),e=$("#message"),b=$("#message-form"),d=$("#message-label"),new Layout(function(){var h;return e.width(b.width()-d.width()-32),h=a.height()-b.height()-10,g.css("max-height",h),c.css("max-height",h-f.outerHeight()-10)})},a}();var ServicesPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};ServicesPage=function(){function f(a){this.session=a,this.api=new Api(this.session),this.selectedService=null,this.validateTimeout=null,this.layout=null,this.users=[]}var a,b,c,d,e;return c="http://getvines.com/protocol/services",b="http://getvines.com/protocol/services/members",d="http://getvines.com/protocol/systems",a="http://getvines.com/protocol/systems/attributes",e="http://getvines.com/protocol/users",f.prototype.deleteService=function(a){var b;return this.drawBlankSlate(),this.toggleForm("#remove-contact-form"),b=$("#services li[data-id='"+this.selectedService.id+"']"),this.api.remove(c,this.selectedService.id,__bind(function(a){return b.fadeOut(200,function(){return b.remove(),this.selectedService=null})},this)),!1},f.prototype.icon=function(a){var b,c;return c={darwin:"mac.png",linux:"linux.png",windows:"windows.png"},b=c[a.os]||"run.png","images/"+b},f.prototype.drawMember=function(a){var b;if(!this.editorVisible())return;return b=$('<li>\n <span class="icon"><img src="'+this.icon(a)+'"/></span>\n <span class="text"></span>\n</li>').appendTo("#members"),$(".text",b).text(a.name)},f.prototype.operators=function(){var a,b,c,d,e,f;e=["like","not like","starts with","ends with","is","is not",">",">=","<","<=","and","or"],f=[];for(c=0,d=e.length;c<d;c++)b=e[c],a=$('<li data-selector="'+b+'">\n '+b+"\n</li>").appendTo("#operators"),f.push(a.click(__bind(function(a){var b;return $("#syntax").focus(),b=$(a.currentTarget).attr("data-selector"),$("#syntax").val($("#syntax").val()+(" "+b+" ")),this.validateIn()},this)));return f},f.prototype.selectService=function(a){var b,d;return b=$(a).attr("data-id"),d=$(a).attr("data-name"),$("#services li").removeClass("selected"),$(a).addClass("selected"),$("#remove-service-msg").html("Are you sure you want to remove the "+("<strong>"+d+"</strong> service?")),$("#remove-service-form .buttons").fadeIn(200),this.api.get(c,{id:b},__bind(function(a){return this.selectedService=a,this.drawEditor(a)},this))},f.prototype.serviceNode=function(a){var b,c;return b=a.size===1?"system":"systems",c=$('<li data-id="'+a.id+'" data-name="" data-size="'+a.size+'">\n <span class="text">'+a.name+'</span>\n <span class="count">'+a.size+" "+b+"</span>\n</li>").appendTo("#services"),c.attr("data-name",a.name),$(".text",c).text(a.name),c.click(__bind(function(a){return this.selectService(a.currentTarget)},this)),c},f.prototype.findServices=function(){return this.api.get(c,{},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.serviceNode(b));return f},this))},f.prototype.findMembers=function(a){return this.api.get(b,{id:a},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.drawMember(b));return f},this))},f.prototype.findUsers=function(a){return this.api.get(e,{},__bind(function(a){var b;return this.users=function(){var c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],b.system||f.push(b);return f}(),this.drawUsers()},this))},f.prototype.attributeNode=function(a){var b;return b=$('<li data-name=""></li>').appendTo("#attributes"),b.text(a),b.attr("data-name",a),b.click(__bind(function(a){var b;return $("#syntax").focus(),b=$(a.currentTarget).attr("data-name"),$("#syntax").val($("#syntax").val()+(" "+b+" ")),this.validateIn()},this))},f.prototype.findAttributes=function(b){return this.api.get(a,{},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.attributeNode(b));return f},this))},f.prototype.validateIn=function(a){return clearTimeout(this.validateTimeout),this.validateTimeout=setTimeout(__bind(function(){return this.validate()},this),a||500)},f.prototype.validate=function(){var a,c;$("#syntax-status").text(""),c=$("#syntax").data("prev"),a=$.trim($("#syntax").val()),$("#syntax").data("prev",a);if(!a||a===c)return;return $("#syntax-status").text("Searching . . ."),$("#members").empty(),this.api.get2(b,a,__bind(function(a){var b,c,d,e,f;if(a.ok){$("#syntax-status").text(""),e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.drawMember(b));return f}return $("#syntax-status").text(a.error)},this))},f.prototype.validateForm=function(){var a,b;return $("#name-error").empty(),b=!0,a=$.trim($("#name").val()),a===""&&($("#name-error").text("Name is required."),b=!1),b},f.prototype.save=function(){var a,b,d,e;if(!this.validateForm())return;return e=$("#users :checked").map(function(){return $(this).val()}).get(),a=$("#unix-users").val().split(","),a=function(){var b,c,e;e=[];for(b=0,c=a.length;b<c;b++)d=a[b],$.trim(d).length>0&&e.push($.trim(d));return e}(),b={name:$("#name").val(),code:$("#syntax").val(),accounts:a,users:e},$("#id").val().length>0&&(b.id=$("#id").val()),this.api.save(c,b,__bind(function(a){var b;return new Notification("Service saved successfully"),a.size=$("#members").length,$("#id").val(a.id),b=$("#services li[data-id='"+a.id+"']"),b.length===0?(b=this.serviceNode(a),this.selectService(b)):$(".text",b).text(a.name)},this)),!1},f.prototype.drawBlankSlate=function(){return $("#beta").empty(),$('<form id="blank-slate">\n <p>\n Services are dynamically updated groups of systems based on\n criteria you define. Send a command to the service and it runs\n on every system in the group.\n </p>\n <input type="submit" id="blank-slate-add" value="Add Service"/>\n</form>').appendTo("#beta"),this.api.user.permissions.services||$("#blank-slate-add").remove(),$("#blank-slate").submit(__bind(function(){return this.drawEditor(),!1},this))},f.prototype.draw=function(){var a;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","services-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Services <div id="search-services-icon"></div></h2>\n <div id="search-services-form"></div>\n <ul id="services" class="selectable scroll y-fill"></ul>\n <div id="alpha-controls" class="controls">\n <div id="add-service"></div>\n <div id="remove-service"></div>\n </div>\n <form id="remove-service-form" class="overlay" style="display:none;">\n <h2>Remove Service</h2>\n <p id="remove-service-msg">Select a service in the list above to remove.</p>\n <fieldset class="buttons" style="display:none;">\n <input id="remove-service-cancel" type="button" value="Cancel"/>\n <input id="remove-service-ok" type="submit" value="Remove"/>\n </fieldset>\n </form>\n</div>\n<div id="beta" class="primary column x-fill y-fill"></div>\n<div id="charlie" class="sidebar column y-fill">\n <h2>Operators</h2>\n <ul id="operators"></ul>\n <h2>Attributes <div id="search-attributes-icon"></div></h2>\n <div id="search-attributes-form"></div>\n <ul id="attributes" class="y-fill scroll"></ul>\n</div>').appendTo("#container"),new Button("#add-service",ICONS.plus),new Button("#remove-service",ICONS.minus),this.api.user.permissions.services||$("#alpha-controls div").remove(),this.drawBlankSlate(),$("#add-service").click(__bind(function(){return this.drawEditor()},this)),$("#remove-service").click(__bind(function(){return this.toggleForm("#remove-service-form")},this)),$("#remove-service-cancel").click(__bind(function(){return this.toggleForm("#remove-service-form")},this)),$("#remove-service-form").submit(__bind(function(){return this.deleteService()},this)),this.operators(),this.findServices(),this.findAttributes(),this.findUsers(),$("#container").show(),this.layout=this.resize(),a=__bind(function(){return this.layout.resize(),this.layout.resize()},this),new Filter({list:"#services",icon:"#search-services-icon",form:"#search-services-form",attrs:["data-name"],open:a,close:a}),new Filter({list:"#attributes",icon:"#search-attributes-icon",form:"#search-attributes-form",attrs:["data-name"],open:a,close:a})},f.prototype.drawEditor=function(a){if(!this.pageVisible())return;return a||(this.selectedService=null,$("#services li").removeClass("selected")),$("#beta").empty(),$('<form id="editor-form" class="sections y-fill scroll">\n <input id="id" type="hidden"/>\n <div>\n <section>\n <h2>Service</h2>\n <fieldset>\n <label for="name">Name</label>\n <input id="name" type="text"/>\n <p id="name-error" class="error"></p>\n <label for="syntax">Criteria</label>\n <textarea id="syntax" placeholder="fqdn starts with \'www.\' and platform is \'mac_os_x\'"></textarea>\n <p id="syntax-status"></p>\n </fieldset>\n </section>\n <section>\n <h2>Members</h2>\n <fieldset id="service-preview">\n <ul id="members" class="scroll"></ul>\n </fieldset>\n </section>\n <section>\n <h2>Permissions</h2>\n <fieldset>\n <label>Users</label>\n <ul id="users" class="scroll"></ul>\n <label for="unix-users">Unix Accounts</label>\n <input id="unix-users" type="text"/>\n </fieldset>\n </section>\n </div>\n</form>\n<form id="editor-buttons">\n <input id="save" type="submit" value="Save"/>\n</form>').appendTo("#beta"),a&&(this.findMembers(a.id),$("#id").val(a.id),$("#name").val(a.name),$("#syntax").val(a.code),$("#unix-users").val(a.accounts.join(", "))),this.users.length>0&&this.drawUsers(),this.layout.resize(),$("#name").focus(),$("#syntax").change(__bind(function(){return this.validateIn()},this)),$("#syntax").keyup(__bind(function(){return this.validateIn()},this)),$("#editor-form").submit(__bind(function(){return this.save()},this)),$("#editor-buttons").submit(__bind(function(){return this.save()},this))},f.prototype.drawUsers=function(){var a,b,c,d,e;if(!this.editorVisible())return;$("#users").empty(),e=this.users;for(c=0,d=e.length;c<d;c++)b=e[c],a=$("<li>\n <input id='user-"+b.jid+"' type='checkbox' value='"+b.jid+"'/>\n <label for='user-"+b.jid+"'>"+b.jid+"</label>\n</li>").appendTo("#users"),b.jid===this.session.bareJid()&&$("input",a).prop("checked",!0);if(this.selectedService)return $('#users input[type="checkbox"]').val(this.selectedService.users)},f.prototype.toggleForm=function(a,b){return a=$(a),$("form.overlay").each(function(){if(this.id!==a.attr("id"))return $(this).hide()}),a.is(":hidden")?(b&&b(),a.fadeIn(100)):a.fadeOut(100,function(){a[0].reset();if(b)return b()})},f.prototype.pageVisible=function(){return $("#services-page").length>0},f.prototype.editorVisible=function(){return $("#services-page #editor-form").length>0},f.prototype.resize=function(){var a,b,c;return a=$("#alpha"),b=$("#beta"),c=$("#charlie"),new Layout(function(){return c.css("left",a.width()+b.width())})},f}();var FilesPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};FilesPage=function(){function d(a){this.session=a,this.api=new Api(this.session),this.uploads=new c({session:this.session,jid:this.api.jid,size:this.size,complete:__bind(function(a){return this.findFile(a.name)},this)})}var a,b,c;return a="http://getvines.com/protocol/files",b="http://getvines.com/protocol/files/labels",d.prototype.findLabels=function(){return $("#labels").empty(),this.api.get(b,{},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.labelNodeList(b));return f},this))},d.prototype.labelNodeList=function(a){var b,c;return c=a.size===1?"file":"files",b=$('<li data-name="">\n <span class="text"></span>\n <span class="count">'+a.size+" "+c+"</span>\n</li>").appendTo("#labels"),$(".text",b).text(a.name),b.attr("data-name",a.name),b.click(__bind(function(a){return this.selectLabel(a)},this))},d.prototype.selectLabel=function(a){var b;return b=$(a.currentTarget).attr("data-name"),$("#labels li").removeClass("selected"),$(a.currentTarget).addClass("selected"),$("#files").empty(),this.findFiles({label:$(a.currentTarget).attr("data-name")})},d.prototype.findFiles=function(b){return this.api.get(a,b,__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.fileNode(b));return f},this))},d.prototype.findFile=function(b){return this.api.get(a,{name:b},__bind(function(a){return this.fileNode(a)},this))},d.prototype.updateFileNode=function(a){var b,c,d;return b=$("#files li[data-id='"+a.id+"']"),c=this.size(a.size),d=this.date(a.created_at),b.data("file",a),$("h2",b).text(a.name),$(".size",b).text(c),$(".time",b).text(d),b.attr("data-name",a.name),b.attr("data-size",c),b.attr("data-created",d)},d.prototype.fileNode=function(a){var b,c,d,e,f,g;if($("#files li[data-id='"+a.id+"']").length>0){this.updateFileNode(a);return}c=$('<li data-id="'+a.id+'">\n <div class="file-icon">\n <span class="size"></span>\n </div>\n <h2></h2>\n <footer>\n <span class="time"></span>\n <ul class="labels"></ul>\n <form class="add-label">\n <div class="add-label-button"></div>\n <input type="text" placeholder="Label" style="display:none;"/>\n </form>\n </footer>\n <form class="file-form">\n <fieldset>\n <input class="cancel" type="submit" value="Delete"/>\n </fieldset>\n </form>\n</li>').appendTo("#files"),new Button($(".file-icon",c).get(0),ICONS.page2,{scale:1,translation:"-2 0","stroke-width":.1,opacity:1}),new Button($(".add-label-button",c).get(0),ICONS.plus,{translation:"-10 -10",scale:.5}),$("form.file-form",c).submit(__bind(function(){return this.deleteFile(c)},this)),$("form.add-label",c).submit(__bind(function(){return this.addLabel(c)},this)),$(".add-label-button",c).click(function(){return $('form.add-label input[type="text"]',c).show()}),this.updateFileNode(a),f=a.labels,g=[];for(d=0,e=f.length;d<e;d++)b=f[d],g.push(this.labelNode(c,b));return g},d.prototype.labelNode=function(a,b){var c,d;return d=$(".labels",a),c=$('<li data-name="">\n <span class="text"></span>\n <div class="remove"></div>\n</li>').appendTo(d),$(".text",c).text(b),c.attr("data-name",b),new Button($(".remove",c).get(0),ICONS.cross,{translation:"-8 -8",scale:.5}),$(".remove",c).click(__bind(function(){return this.removeLabel(a,c)},this))},d.prototype.addLabel=function(b){var c,d,e,f,g,h,i,j,k;d=$('form.add-label input[type="text"]',b),d.hide(),f=function(){var a,b,c,e;c=d.val().split(/,/),e=[];for(a=0,b=c.length;a<b;a++)g=c[a],g&&e.push(g);return e}(),d.val(""),c=b.data("file");for(h=0,j=f.length;h<j;h++)e=f[h],c.labels.push(e);this.api.save(a,c,function(a){});for(i=0,k=f.length;i<k;i++)e=f[i],this.labelNode(b,e),this.updateLabelCount(e,1);return!1},d.prototype.removeLabel=function(b,c){var d,e,f;return d=b.data("file"),f=c.attr("data-name"),d.labels=function(){var a,b,c,g;c=d.labels,g=[];for(a=0,b=c.length;a<b;a++)e=c[a],e!==f&&g.push(e);return g}(),this.api.save(a,d,function(a){}),c.fadeOut(200,function(){return c.remove()}),this.updateLabelCount(f,-1)},d.prototype.updateLabelCount=function(a,b){var c,d,e;return d=$("#labels li[data-name='"+a+"'] .count"),d.length>0?(c=parseInt(d.text().split(" ")[0])+b,e=c===1?"file":"files",d.text(""+c+" "+e)):this.labelNodeList({name:a,size:1})},d.prototype.deleteFile=function(b){return this.api.remove(a,b.attr("data-id"),__bind(function(a){var c,d,e,f;f=b.data("file").labels;for(d=0,e=f.length;d<e;d++)c=f[d],this.updateLabelCount(c,-1);return b.fadeOut(200,function(){return b.remove()})},this)),!1},d.prototype.date=function(a){var b,c;return a=new Date(a),b="Sun Mon Tue Wed Thu Fri Sat".split(" ")[a.getDay()],c="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ")[a.getMonth()],""+b+", "+a.getDate()+" "+c+", "+a.getFullYear()+" @ "+a.getHours()+":"+a.getMinutes()},d.prototype.size=function(a){var b,c,d,e;return d=a/1024,e=d/1024,c=e/1024,b=function(a){return a<100?a.toFixed(1).replace(".0",""):Math.round(a)},d<1?""+a+" b":e<1?""+b(d)+" k":c<1?""+b(e)+" m":""+b(c)+" g"},d.prototype.draw=function(){var a,b;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","files-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Labels</h2>\n <ul id="labels" class="selectable scroll y-fill"></ul>\n <div id="alpha-controls" class="controls"></div>\n</div>\n<div id="beta" class="primary column x-fill y-fill">\n <h2 id="files-title">Files <div id="search-files-icon"></div></h2>\n <div id="search-files-form"></div>\n <ul id="files" class="scroll y-fill"></ul>\n</div>\n<div id="charlie" class="sidebar column y-fill">\n <h2>Uploads</h2>\n <div id="upload-dnd" class="float">Drag files here to upload.</div>\n <ul id="uploads" class="scroll y-fill"></ul>\n <div id="charlie-controls" class="controls">\n <form id="file-form">\n <input id="open-file-chooser" type="submit" value="Select files to upload"/>\n <input id="file-chooser" type="file" multiple="true" />\n </form>\n </div>\n</div>').appendTo("#container"),this.api.user.permissions.files?($("#file-chooser").change(__bind(function(a){return this.uploads.queue(a.target.files),$("#file-chooser").val("")},this)),$("#file-form").submit(function(){return $("#file-chooser").click(),!1}),$("#upload-dnd").bind("dragenter",function(a){return a.stopPropagation(),a.preventDefault(),$("#upload-dnd").css("color","#444")}),$("#upload-dnd").bind("dragleave",function(a){return $("#upload-dnd").css("color","#ababab")}),$("#upload-dnd").bind("dragover",function(a){return a.stopPropagation(),a.preventDefault()}),$("#upload-dnd").bind("drop",__bind(function(a){return a.stopPropagation(),a.preventDefault(),$("#upload-dnd").css("color","#ababab"),this.uploads.queue(a.originalEvent.dataTransfer.files)},this))):($("#upload-dnd").text("Your account cannot upload files."),$("#file-form").remove()),this.findLabels(),this.findFiles(),$("#container").show(),b=this.resize(),a=function(){return b.resize(),b.resize()},new Filter({list:"#files",icon:"#search-files-icon",form:"#search-files-form",attrs:["data-name","data-created"],open:a,close:a})},d.prototype.resize=function(){var a,b,c,d,e;return a=$("#alpha"),b=$("#beta"),c=$("#charlie"),e=$("#uploads"),d=$("#upload-dnd"),new Layout(function(){return c.css("left",a.width()+b.width()),d.height(e.height()),d.css("line-height",e.height()+"px")})},c=function(){function a(a){this.session=a.session,this.serviceJid=a.jid,this.size=a.size,this.complete=a.complete,this.uploads=[],this.sending=null}return a.prototype.queue=function(a){var b,c,d;for(c=0,d=a.length;c<d;c++)b=a[c],this.find(b)||this.add(b);return this.process()},a.prototype.add=function(a){var b,c;return c=this.node(a),b=$(".meter",c),this.uploads.push(new Transfer({to:this.serviceJid(),file:a,session:this.session,progress:function(a){return b.css("width",a+"%")},complete:__bind(function(){return this.remove(a),this.complete&&this.complete(a),a.name===this.sending.name&&(this.sending=null),this.process()},this)}))},a.prototype.process=function(){var a;if(this.sending)return;return(a=this.uploads[0])?(this.sending=a.file,a.start()):this.sending=null},a.prototype.find=function(a){var b;return function(){var c,d,e,f;e=this.uploads,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],b.file.name===a.name&&f.push(b);return f}.call(this).shift()},a.prototype.remove=function(a){var b,c;return this.uploads=function(){var b,d,e,f;e=this.uploads,f=[];for(b=0,d=e.length;b<d;b++)c=e[b],c.file.name!==a.name&&f.push(c);return f}.call(this),b=$("#uploads li[data-file='"+a.name+"']"),b.fadeOut(200,function(){return b.remove()})},a.prototype.node=function(a){var b;return b=$('<li data-file="" style="display:none;">\n <form class="inset">\n <h2></h2>\n <div class="progress">\n <div class="meter"></div>\n <span class="text">'+this.size(a.size)+'</span>\n <div class="cancel"></div>\n </div>\n </form>\n</li>').appendTo("#uploads"),b.fadeIn(200),$("h2",b).text(a.name),b.attr("data-file",a.name),new Button($(".cancel",b).get(0),ICONS.cross,{translation:"-8 -8",scale:.5}),$(".cancel",b).click(__bind(function(){return this.cancel(a)},this)),b},a.prototype.cancel=function(a){var b;if(b=this.find(a))return b.stop()},a}(),d}();var SetupPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};SetupPage=function(){function d(a){this.session=a,this.api=new Api(this.session),this.layout=null,this.selected=null,this.services=[],this.users=[]}var a,b,c;return a="http://getvines.com/protocol/services",b="http://getvines.com/protocol/systems",c="http://getvines.com/protocol/users",d.prototype.findSystem=function(a){return this.api.get(b,{name:a},__bind(function(a){return this.drawSystemInfo(a)},this))},d.prototype.findServices=function(){return this.api.get(a,{},__bind(function(a){return this.services=a.rows,this.drawServices()},this))},d.prototype.drawServices=function(){var a,b,c,d,e;if($("#setup-page #services").length===0)return;$("#services").empty(),e=this.services;for(c=0,d=e.length;c<d;c++)b=e[c],a=$("<li>\n <input id='service-"+b.id+"' type='checkbox' value='"+b.id+"'/>\n <label for='service-"+b.id+"'></label>\n</li>").appendTo("#services"),$("label",a).text(b.name);this.selected&&$('#services input[type="checkbox"]').val(this.selected.services);if(this.selected&&!this.api.user.permissions.services)return $('#services input[type="checkbox"]').prop("disabled",!0)},d.prototype.findUsers=function(){return this.api.get(c,{},__bind(function(a){return this.users=a.rows,this.drawUsers()},this))},d.prototype.drawUsers=function(){var a,b,c,d,e,f;if($("#setup-page #users").length===0)return;$("#users").empty(),a=$("#systems-nav").hasClass("selected"),e=this.users,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(b.system===a?this.userNode(b):void 0);return f},d.prototype.userNode=function(a){var b,c;return c=$('<li data-name="" data-jid="'+a.jid+'" id="'+a.jid+'">\n <span class="text"></span>\n <span class="jid">'+a.jid+"</span>\n</li>").appendTo("#users"),b=this.userName(a),$(".text",c).text(b),c.attr("data-name",b),c.click(__bind(function(a){return this.selectUser(a.currentTarget)},this)),c},d.prototype.userName=function(a){return a.name||a.jid.split("@")[0]},d.prototype.selectUser=function(a){var b,d;return b=$(a).attr("data-jid"),d=$(a).attr("data-name"),$("#users li").removeClass("selected"),$(a).addClass("selected"),$("#remove-user-msg").html("Are you sure you want to remove "+("<strong>"+d+"</strong>?")),$("#remove-user-form .buttons").fadeIn(200),this.api.get(c,{jid:b},__bind(function(a){return this.selected=a,a.system?this.drawSystemEditor(a):this.drawUserEditor(a)},this))},d.prototype.removeUser=function(){var a;return this.toggleForm("#remove-user-form"),a=$("#users li[data-jid='"+this.selected.jid+"']"),this.api.remove(c,this.selected.jid,__bind(function(b){return a.fadeOut(200,__bind(function(){var b;return this.users=function(){var a,c,d,e;d=this.users,e=[];for(a=0,c=d.length;a<c;a++)b=d[a],b.jid!==this.selected.jid&&e.push(b);return e}.call(this),a.remove(),this.selected=null,$("#users-nav").hasClass("selected")?this.drawUserBlankSlate():this.drawSystemBlankSlate()},this))},this)),!1},d.prototype.selectTask=function(a){this.selected=null,$("#setup li").removeClass("selected secondary"),$(a.currentTarget).addClass("selected secondary");switch($(a.currentTarget).attr("id")){case"users-nav":return $("#beta-header").text("Users"),this.drawUsers(),this.drawUserBlankSlate(),this.api.user.permissions.users?$("#beta-controls div").show():$("#beta-controls div").hide();case"systems-nav":return $("#beta-header").text("Systems"),this.drawUsers(),this.drawSystemBlankSlate(),this.api.user.permissions.systems?$("#beta-controls div").show():$("#beta-controls div").hide()}},d.prototype.toggleForm=function(a,b){return a=$(a),$("form.overlay").each(function(){if(this.id!==a.attr("id"))return $(this).hide()}),a.is(":hidden")?(b&&b(),a.fadeIn(100)):a.fadeOut(100,function(){a[0].reset();if(b)return b()})},d.prototype.validateUser=function(){var a,b,c,d;$("#user-name-error").empty(),$("#password-error").empty(),d=!0,a=$.trim($("#user-name").val()),b=$.trim($("#password1").val()),c=$.trim($("#password2").val());if(this.selected)c.length>0&&c.length<8&&($("#password-error").text("Password must be at least 8 characters."
|
2
|
-
),d=!1),this.session.bareJid()!==this.selected.jid&&b!==c&&($("#password-error").text("Passwords must match."),d=!1);else{a===""&&($("#user-name-error").text("User name is required."),d=!1),a.match(/[\s"&'\/:<>@]/)&&($("#user-name-error").text("User name contains forbidden characters."),d=!1);if(b.length===0||c.length===0)$("#password-error").text("Password is required."),d=!1;b!==c&&($("#password-error").text("Passwords must match."),d=!1),c.length<8&&($("#password-error").text("Password must be at least 8 characters."),d=!1)}return d},d.prototype.saveUser=function(){var a;return this.validateUser()?(a={jid:$("#jid").val(),username:$("#user-name").val(),name:$("#name").val(),password1:$("#password1").val(),password2:$("#password2").val(),services:$("#services :checked").map(function(){return $(this).val()}).get(),permissions:{systems:$("#perm-systems").prop("checked"),services:$("#perm-services").prop("checked"),files:$("#perm-files").prop("checked"),users:$("#perm-users").prop("checked")}},this.api.save(c,a,__bind(function(a){var b;return new Notification("User saved successfully"),$("#jid").val(a.jid),b=$("#users li[data-jid='"+a.jid+"']"),b.length===0?(this.users.push(a),b=this.userNode(a),this.selectUser(b)):$(".text",b).text(this.userName(a))},this)),!1):!1},d.prototype.validateSystem=function(){var a,b;return $("#user-name-error").empty(),b=!0,a=$.trim($("#user-name").val()),this.selected||(a===""&&($("#user-name-error").text("Hostname is required."),b=!1),a.match(/[\s"&'\/:<>@]/)&&($("#user-name-error").text("Hostname contains forbidden characters."),b=!1)),b},d.prototype.saveSystem=function(){var a;return this.validateSystem()?(a={jid:$("#jid").val(),username:$("#user-name").val(),password1:$("#password1").val(),password2:$("#password1").val(),system:!0},this.api.save(c,a,__bind(function(a){var b;return new Notification("System saved successfully"),$("#jid").val(a.jid),b=$("#users li[data-jid='"+a.jid+"']"),b.length===0?(this.users.push(a),b=this.userNode(a),this.selectUser(b)):$(".text",b).text(a.name)},this)),!1):!1},d.prototype.rand=function(){return Math.floor(Math.random()*16)},d.prototype.token=function(){var a;return function(){var b;b=[];for(a=0;a<=127;a++)b.push(this.rand().toString(16));return b}.call(this).join("")},d.prototype.drawUserBlankSlate=function(){var a;return $("#charlie").empty(),a=this.api.user.permissions.users?"Select a user account to update or add a new user.":"Select a user account to update.",$('<form id="blank-slate">\n <p>'+a+'</p>\n <input type="submit" id="blank-slate-add" value="Add User"/>\n</form>').appendTo("#charlie"),this.api.user.permissions.users||$("#blank-slate-add").remove(),$("#blank-slate").submit(__bind(function(){return this.drawUserEditor(),!1},this))},d.prototype.drawSystemBlankSlate=function(){return $("#charlie").empty(),$('<form id="blank-slate">\n <p>\n Systems need a user account before they can connect and\n authenticate with the chat server.\n </p>\n <input type="submit" id="blank-slate-add" value="Add System"/>\n</form>').appendTo("#charlie"),this.api.user.permissions.systems||$("#blank-slate-add").remove(),$("#blank-slate").submit(__bind(function(){return this.drawSystemEditor(),!1},this))},d.prototype.draw=function(){var a;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","setup-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Setup</h2>\n <ul id="setup" class="selectable scroll y-fill">\n <li id="users-nav" class=\'selected secondary\'>\n <span class="text">Users</span>\n </li>\n <li id="systems-nav">\n <span class="text">Systems</span>\n </li>\n </ul>\n <div id="alpha-controls" class="controls"></div>\n</div>\n<div id="beta" class="sidebar column y-fill">\n <h2><span id="beta-header">Users</span> <div id="search-users-icon"></div></h2>\n <div id="search-users-form"></div>\n <ul id="users" class="selectable scroll y-fill"></ul>\n <form id="remove-user-form" class="overlay" style="display:none;">\n <h2>Remove User</h2>\n <p id="remove-user-msg">Select a user to delete.</p>\n <fieldset class="buttons" style="display:none;">\n <input id="remove-user-cancel" type="button" value="Cancel"/>\n <input id="remove-user-ok" type="submit" value="Remove"/>\n </fieldset>\n </form>\n <div id="beta-controls" class="controls">\n <div id="add-user"></div>\n <div id="remove-user"></div>\n </div>\n</div>\n<div id="charlie" class="primary column x-fill y-fill"></div>').appendTo("#container"),this.drawUserBlankSlate(),$("#setup li").click(__bind(function(a){return this.selectTask(a)},this)),this.findUsers(),this.findServices(),$("#container").show(),this.layout=this.resize(),new Button("#add-user",ICONS.plus),new Button("#remove-user",ICONS.minus),this.api.user.permissions.users||$("#beta-controls div").hide(),this.api.user.permissions.systems||$("#systems-nav").hide(),$("#add-user").click(__bind(function(){return $("#users-nav").hasClass("selected")?this.drawUserEditor():this.drawSystemEditor()},this)),$("#remove-user").click(__bind(function(){return this.toggleForm("#remove-user-form")},this)),$("#remove-user-cancel").click(__bind(function(){return this.toggleForm("#remove-user-form")},this)),$("#remove-user-form").submit(__bind(function(){return this.removeUser()},this)),a=__bind(function(){return this.layout.resize(),this.layout.resize()},this),new Filter({list:"#users",icon:"#search-users-icon",form:"#search-users-form",attrs:["data-jid","data-name"],open:a,close:a})},d.prototype.drawUserEditor=function(a){var b,c,d,e;a||(this.selected=null,$("#users li").removeClass("selected")),$("#charlie").empty(),$('<form id="editor-form" class="sections y-fill scroll">\n <div>\n <section>\n <h2>User</h2>\n <fieldset id="jid-fields">\n <input id="jid" type="hidden" value=""/>\n <label for="name">Real Name</label>\n <input id="name" type="text" maxlength="1024"/>\n </fieldset>\n </section>\n <section>\n <h2>Password</h2>\n <fieldset>\n <label id="password1-label" for="password1">Current Password</label>\n <input id="password1" type="password" maxlength="1024"/>\n <label id="password2-label" for="password2">New Password</label>\n <input id="password2" type="password" maxlength="1024"/>\n <p id="password-error" class="error"></p>\n </fieldset>\n </section>\n <section>\n <h2>Permissions</h2>\n <fieldset>\n <label>Manage</label>\n <ul id="permissions">\n <li>\n <input id="perm-systems" type="checkbox" value="systems"/>\n <label for="perm-systems">Systems</label>\n </li>\n <li>\n <input id="perm-services" type="checkbox" value="services"/>\n <label for="perm-services">Services</label>\n </li>\n <li>\n <input id="perm-users" type="checkbox" value="users"/>\n <label for="perm-users">Users</label>\n </li>\n <li>\n <input id="perm-files" type="checkbox" value="files"/>\n <label for="perm-files">Files</label>\n </li>\n </ul>\n </fieldset>\n </section>\n <section>\n <h2>Services</h2>\n <fieldset>\n <label>Access To</label>\n <ul id="services" class="scroll"></ul>\n </fieldset>\n </section>\n </div>\n</form>\n<form id="editor-buttons">\n <input id="save" type="submit" value="Save"/>\n</form>').appendTo("#charlie");if(a){$("<label>Account Name</label>\n<p>"+a.jid+"</p>").prependTo("#jid-fields"),$("#name").focus(),this.session.bareJid()!==a.jid&&($("#password1-label").text("Password"),$("#password2-label").text("Password Again")),$("#jid").val(a.jid),$("#name").val(a.name),$("#user-name").val(a.jid.split("@")[0]),e="services systems files users".split(" ");for(c=0,d=e.length;c<d;c++)b=e[c],a.permissions[b]&&$("#perm-"+b).prop("checked",!0),this.session.bareJid()===a.jid&&$("#perm-"+b).prop("disabled",!0)}else $('<label for="user-name">User Name</label>\n<input id="user-name" type="text" maxlength="1023"/>\n<p id="user-name-error" class="error"></p>').prependTo("#jid-fields"),$("#password1-label").text("Password"),$("#password2-label").text("Password Again"),$("#user-name").focus();return this.services.length>0&&this.drawServices(),this.layout.resize(),$("#editor-form").submit(__bind(function(){return this.saveUser()},this)),$("#editor-buttons").submit(__bind(function(){return this.saveUser()},this))},d.prototype.drawSystemEditor=function(a){return a||(this.selected=null,$("#users li").removeClass("selected")),$("#charlie").empty(),$('<form id="editor-form" class="sections y-fill scroll">\n <div>\n <section>\n <h2>System</h2>\n <fieldset id="jid-fields">\n <input id="jid" type="hidden" value=""/>\n <label id="password1-label" for="password1">Authentication Token</label>\n <div id="token-container">\n <input id="password1" type="text" readonly placeholder="Press Generate to create a new token"/>\n <input id="new-token" type="button" value="Generate"/>\n </div>\n </fieldset>\n </section>\n <section id="info">\n <h2>Info</h2>\n <fieldset>\n <label>Platform</label>\n <p id="info-platform">-</p>\n <label>Hostname</label>\n <p id="info-fqdn">-</p>\n <label>IP Address</label>\n <p id="info-ip">-</p>\n <label>MAC Address</label>\n <p id="info-mac">-</p>\n </fieldset>\n </section>\n </div>\n</form>\n<form id="editor-buttons">\n <input id="save" type="submit" value="Save"/>\n</form>').appendTo("#charlie"),$("#new-token").click(__bind(function(){return $("#password1").val(this.token())},this)),a&&this.findSystem(a.jid.split("@")[0]),a?($("<label>Account Name</label>\n<p>"+a.jid+"</p>").prependTo("#jid-fields"),$("#jid").val(a.jid),$("#user-name").val(a.jid.split("@")[0])):($('<label for="user-name">Hostname</label>\n<input id="user-name" type="text" maxlength="1023"/>\n<p id="user-name-error" class="error"></p>').prependTo("#jid-fields"),$("#user-name").focus(),$("#password1").val(this.token())),this.layout.resize(),$("#editor-form").submit(__bind(function(){return this.saveSystem()},this)),$("#editor-buttons").submit(__bind(function(){return this.saveSystem()},this))},d.prototype.drawSystemInfo=function(a){return $("#info-platform").text(a.platform),$("#info-fqdn").text(a.fqdn),$("#info-ip").text(a.ipaddress),$("#info-mac").text(a.macaddress)},d.prototype.resize=function(){var a,b,c;return a=$("#alpha"),b=$("#beta"),c=$("#charlie"),new Layout(function(){return c.css("left",a.outerWidth()+b.outerWidth())})},d}(),$(function(){var a,b,c,d,e,f;f=new Session,d=new NavBar(f),d.draw(),a={Systems:ICONS.commandline,Services:ICONS.magic,Files:ICONS.page2,Setup:ICONS.gear2,Logout:ICONS.power};for(c in a)b=a[c],d.addButton(c,b);return e={"/systems":new SystemsPage(f),"/services":new ServicesPage(f),"/files":new FilesPage(f),"/setup":new SetupPage(f),"/logout":new LogoutPage(f),"default":new LoginPage(f,"/systems/")},(new Router(e)).draw(),d.select($("#nav-link-systems").parent())})
|
1
|
+
var Api,__bind=function(a,b){return function(){return a.apply(b,arguments)}};Api=function(){function b(b){this.session=b,this.user=null,this.session.onRoster(__bind(function(){return this.get(a,{jid:this.session.bareJid()},__bind(function(a){return this.user=a},this))},this))}var a;return a="http://getvines.com/protocol/users",b.prototype.jid=function(){return"vines."+this.session.bareJid().split("@")[1]},b.prototype.get=function(a,b,c){var d,e,f;e=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="get">\n <query xmlns="'+a+'"/>\n</iq>');for(d in b)f=b[d],$("query",e).attr(d,f);return this.session.sendIQ(e,__bind(function(a){var b;b=$(a).attr("type")==="result";if(!b)return;return c(JSON.parse($("query",a).text()))},this))},b.prototype.get2=function(a,b,c){var d;return d=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="get">\n <query xmlns="'+a+'"/>\n</iq>'),$("query",d).text(b),this.session.sendIQ(d,__bind(function(a){var b;b=$(a).attr("type")==="result";if(!b)return;return c(JSON.parse($("query",a).text()))},this))},b.prototype.remove=function(a,b,c){var d;return d=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="set">\n <query xmlns="'+a+'" action="delete" id=""/>\n</iq>'),$("query",d).attr("id",b),this.session.sendIQ(d,c)},b.prototype.save=function(a,b,c){var d;return d=this.session.xml('<iq id="'+this.session.uniqueId()+'" to="'+this.jid()+'" type="set">\n <query xmlns="'+a+'"/>\n</iq>'),$("query",d).text(JSON.stringify(b)),this.session.sendIQ(d,__bind(function(a){var b;b=$(a).attr("type")==="result";if(!b)return;return c(JSON.parse($("query",a).text()))},this))},b}();var Commands;Commands=function(){function a(){this.buf=[],this.index=0}return a.prototype.prev=function(){var a;return a=this.buf[--this.index],a||(this.index=-1),a||""},a.prototype.next=function(){var a;return a=this.buf[++this.index],a||(this.index=this.buf.length),a||""},a.prototype.push=function(a){return this.buf.push(a),this.index=this.buf.length},a}();var SystemsPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};SystemsPage=function(){function a(a){this.session=a,this.session.onRoster(__bind(function(){return this.roster()},this)),this.session.onMessage(__bind(function(a){return this.message(a)},this)),this.session.onPresence(__bind(function(a){return this.presence(a)},this)),this.commands=new Commands,this.chats={},this.currentContact=null,this.layout=null}return a.prototype.datef=function(a){var b,c,d,e;return b=new Date(a),d=b.getHours()<12?" am":" pm",c=b.getHours()>12?b.getHours()-12:b.getHours(),c===0&&(c=12),e=b.getMinutes()+"",e.length===1&&(e="0"+e),c+":"+e+d},a.prototype.groupContacts=function(){var a,b,c,d,e,f,g,h;c={},g=this.session.roster;for(d in g){a=g[d],h=a.groups;for(e=0,f=h.length;e<f;e++)b=h[e],(c[b]||(c[b]=[])).push(a)}return c},a.prototype.roster=function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n;d=this.groupContacts(),k=function(){var a;a=[];for(c in d)b=d[c],a.push(c);return a}(),k=k.sort(function(a,b){return a=a.toLowerCase(),b=b.toLowerCase(),a>b?1:a<b?-1:0}),f=$("#roster-items").empty(),n=[];for(l=0,m=k.length;l<m;l++)c=k[l],b=d[c],h=$('<li class="group"></li>').appendTo(f),h.text(c),h.attr("data-group",c),n.push(function(){var d,h,k;k=[];for(d=0,h=b.length;d<h;d++)a=b[d],i=$('<li data-jid="'+a.jid+'">\n <span class="icon"></span>\n <span class="text"></span>\n <span class="unread" style="display:none;"></span>\n</li>').appendTo(f),a.offline()&&i.addClass("offline"),i.click(__bind(function(a){return this.selectContact(a)},this)),g=a.name||a.jid.split("@")[0],i.attr("data-name",g),i.attr("data-group",c),$(".text",i).text(g),j={fill:"#fff",stroke:"#404040","stroke-width":.3,opacity:1,scale:.65},e=function(){switch(c){case"People":return ICONS.man;case"Services":return ICONS.magic;default:return ICONS.run}}(),k.push(new Button($(".icon",i),e,j));return k}.call(this));return n},a.prototype.message=function(a){var b,c,d,e;this.queueMessage(a),e=a.from===this.session.jid(),d=a.from.split("/")[0];if(!e&&d!==this.currentContact)return c=this.chat(a.from),c.unread++,this.eachContact(d,function(a){return $(".unread",a).text(c.unread).show()});b=this.atBottom(),this.appendMessage(a);if(b||e)return this.scroll({animate:!0})},a.prototype.eachContact=function(a,b){var c,d,e,f,g;f=$("#roster-items li[data-jid='"+a+"']").get(),g=[];for(d=0,e=f.length;d<e;d++)c=f[d],g.push(b($(c)));return g},a.prototype.appendMessage=function(a){var b,c,d,e,f,g,h;d=a.from===this.session.jid(),h=$("jid",a.node).text(),c=(h||a.from).split("/")[0],b=this.session.roster[c],e=b?b.name||c:c,f=$('<li data-jid="'+c+'"><pre></pre></li>').appendTo("#messages"),g=d?"$ ":"",$("pre",f).text(g+a.text),$("#message-form").css("top","0px");if(!d)return f.append('<footer>\n <span class="author"></span> @\n <span class="time">'+this.datef(a.received)+"</span>\n</footer>"),$(".author",f).text(e)},a.prototype.queueMessage=function(a){var b,c,d;return d=a.from===this.session.jid(),c=a[d?"to":"from"],b=this.chat(c),b.jid=c,b.messages.push(a)},a.prototype.chat=function(a){var b,c;return b=a.split("/")[0],c=this.chats[b],c||(c={jid:a,messages:[],unread:0},this.chats[b]=c),c},a.prototype.presence=function(a){var b,c;c=a.from.split("/")[0];if(c===this.session.bareJid())return;if(!a.type||a.offline)b=this.session.roster[c],this.eachContact(c,function(a){return b.offline()?a.addClass("offline"):a.removeClass("offline")});if(a.offline)return this.chat(c).jid=c},a.prototype.selectContact=function(a){var b,c,d;$("#blank-slate").fadeOut(200,function(){return $(this).remove()}),$("#roster").hide(),$("#message").focus(),d=$(a.currentTarget),c=d.attr("data-jid"),b=this.session.roster[c];if(this.currentContact===c)return;return this.currentContact=c,$("#message-label").text($(".text",d).text()),$("#messages").empty(),$("#message-form").css("top","10px"),this.layout.resize(),this.restoreChat(c)},a.prototype.restoreChat=function(a){var b,c,d,e,f;b=this.chats[a],c=[],b&&(c=b.messages,b.unread=0,this.eachContact(a,function(a){return $(".unread",a).text("").hide()}));for(e=0,f=c.length;e<f;e++)d=c[e],this.appendMessage(d);return this.scroll()},a.prototype.scroll=function(a){var b;return a||(a={}),b=$("#messages"),a.animate?b.animate({scrollTop:b.prop("scrollHeight")},400):b.scrollTop(b.prop("scrollHeight"))},a.prototype.atBottom=function(){var a,b;return b=$("#messages"),a=b.prop("scrollHeight")-b.outerHeight(),b.scrollTop()>=a},a.prototype.send=function(){var a,b,c,d;return this.currentContact?(b=$("#message"),d=b.val().trim(),d&&(a=this.chats[this.currentContact],c=a?a.jid:this.currentContact,this.message({from:this.session.jid(),text:d,to:c,received:new Date}),this.session.sendMessage(c,d),this.commands.push(d)),b.val(""),!1):!1},a.prototype.showRoster=function(){var a,b,c,d,e,f,g;return a=$("#container"),b=$("#message-form"),f=$("#roster"),d=$("#roster-items"),e=$("#roster-form"),g=a.height()-b.position().top<a.height()/2,g?(f.css("top",""),f.css("bottom",b.outerHeight()+5+"px"),c=a.height()-b.outerHeight()-20):(f.css("bottom",""),f.css("top",b.position().top+b.outerHeight()+"px"),c=a.height()-b.position().top-30),d.css("max-height",c-e.outerHeight()-40+"px"),f.css("max-height",c+"px"),f.show()},a.prototype.drawBlankSlate=function(){return $('<form id="blank-slate" class="float">\n <p>\n Services, and individual systems, can be controlled by sending\n them shell commands through this terminal. Select a system to chat with\n to get started.\n </p>\n <input type="submit" value="Select System"/>\n</form>').appendTo("#alpha"),$("#blank-slate").submit(__bind(function(){return this.showRoster(),this.layout.resize(),!1},this))},a.prototype.draw=function(){var a,b;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","systems-page"),$("#container").hide().empty(),$('<div id="alpha" class="primary column x-fill y-fill">\n <ul id="messages" class="scroll"></ul>\n <form id="message-form">\n <label id="message-label"></label>\n <input id="message" name="message" type="text" maxlength="1024" placeholder="Type a command and press enter to send"/>\n </form>\n <div id="roster" class="float" style="display:none;">\n <ul id="roster-items"></ul>\n <div id="roster-form"></div>\n </div>\n</div>').appendTo("#container"),$("#message-form").css("top","10px"),$("#message-form").submit(__bind(function(){return this.send()},this)),$("#messages").click(function(){return $("#roster").hide()}),$("#message").focus(function(){return $("#roster").hide()}),$(document).keyup(function(a){if(a.keyCode===27)return $("#roster").hide()}),this.roster(),$("#message-label").click(__bind(function(){var a;return a=$("#roster"),a.is(":visible")?a.hide():this.showRoster()},this)),$("#message").keyup(__bind(function(a){switch(a.keyCode){case 38:return $("#message").val(this.commands.prev());case 40:return $("#message").val(this.commands.next())}},this)),this.currentContact?(this.currentContact&&this.restoreChat(this.currentContact),a=this.session.roster[this.currentContact],b=a.name||a.jid.split("@")[0],$("#message-label").text(b),$("#message").focus()):this.drawBlankSlate(),$("#container").show(),this.layout=this.resize(),this.scroll(),$("#message").focus(),new Filter({list:"#roster-items",form:"#roster-form",attrs:["data-jid","data-name"]}),$("form","#roster-form").show()},a.prototype.resize=function(){var a,b,c,d,e;return a=$("#container"),e=$("#messages"),d=$("#message"),b=$("#message-form"),c=$("#message-label"),new Layout(function(){return d.width(b.width()-c.width()-32),e.css("max-height",a.height()-b.height())})},a}();var ServicesPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};ServicesPage=function(){function f(a){this.session=a,this.api=new Api(this.session),this.selectedService=null,this.validateTimeout=null,this.layout=null,this.users=[]}var a,b,c,d,e;return c="http://getvines.com/protocol/services",b="http://getvines.com/protocol/services/members",d="http://getvines.com/protocol/systems",a="http://getvines.com/protocol/systems/attributes",e="http://getvines.com/protocol/users",f.prototype.deleteService=function(a){var b;return this.drawBlankSlate(),this.toggleForm("#remove-contact-form"),b=$("#services li[data-id='"+this.selectedService.id+"']"),this.api.remove(c,this.selectedService.id,__bind(function(a){return b.fadeOut(200,function(){return b.remove(),this.selectedService=null})},this)),!1},f.prototype.icon=function(a){var b,c;return c={darwin:"mac.png",linux:"linux.png",windows:"windows.png"},b=c[a.os]||"run.png","images/"+b},f.prototype.drawMember=function(a){var b;if(!this.editorVisible())return;return b=$('<li>\n <span class="icon"><img src="'+this.icon(a)+'"/></span>\n <span class="text"></span>\n</li>').appendTo("#members"),$(".text",b).text(a.name)},f.prototype.operators=function(){var a,b,c,d,e,f;e=["like","not like","starts with","ends with","is","is not",">",">=","<","<=","and","or"],f=[];for(c=0,d=e.length;c<d;c++)b=e[c],a=$('<li data-selector="'+b+'">\n '+b+"\n</li>").appendTo("#operators"),f.push(a.click(__bind(function(a){var b;return $("#syntax").focus(),b=$(a.currentTarget).attr("data-selector"),$("#syntax").val($("#syntax").val()+(" "+b+" ")),this.validateIn()},this)));return f},f.prototype.selectService=function(a){var b,d;return b=$(a).attr("data-id"),d=$(a).attr("data-name"),$("#services li").removeClass("selected"),$(a).addClass("selected"),$("#remove-service-msg").html("Are you sure you want to remove the "+("<strong>"+d+"</strong> service?")),$("#remove-service-form .buttons").fadeIn(200),this.api.get(c,{id:b},__bind(function(a){return this.selectedService=a,this.drawEditor(a)},this))},f.prototype.serviceNode=function(a){var b,c;return b=a.size===1?"system":"systems",c=$('<li data-id="'+a.id+'" data-name="" data-size="'+a.size+'">\n <span class="text">'+a.name+'</span>\n <span class="count">'+a.size+" "+b+"</span>\n</li>").appendTo("#services"),c.attr("data-name",a.name),$(".text",c).text(a.name),c.click(__bind(function(a){return this.selectService(a.currentTarget)},this)),c},f.prototype.findServices=function(){return this.api.get(c,{},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.serviceNode(b));return f},this))},f.prototype.findMembers=function(a){return this.api.get(b,{id:a},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.drawMember(b));return f},this))},f.prototype.findUsers=function(a){return this.api.get(e,{},__bind(function(a){var b;return this.users=function(){var c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],b.system||f.push(b);return f}(),this.drawUsers()},this))},f.prototype.attributeNode=function(a){var b;return b=$('<li data-name=""></li>').appendTo("#attributes"),b.text(a),b.attr("data-name",a),b.click(__bind(function(a){var b;return $("#syntax").focus(),b=$(a.currentTarget).attr("data-name"),$("#syntax").val($("#syntax").val()+(" "+b+" ")),this.validateIn()},this))},f.prototype.findAttributes=function(b){return this.api.get(a,{},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.attributeNode(b));return f},this))},f.prototype.validateIn=function(a){return clearTimeout(this.validateTimeout),this.validateTimeout=setTimeout(__bind(function(){return this.validate()},this),a||500)},f.prototype.validate=function(){var a,c;$("#syntax-status").text(""),c=$("#syntax").data("prev"),a=$("#syntax").val().trim(),$("#syntax").data("prev",a);if(!a||a===c)return;return $("#syntax-status").text("Searching . . ."),$("#members").empty(),this.api.get2(b,a,__bind(function(a){var b,c,d,e,f;if(a.ok){$("#syntax-status").text(""),e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.drawMember(b));return f}return $("#syntax-status").text(a.error)},this))},f.prototype.validateForm=function(){var a,b;return $("#name-error").empty(),$("#unix-users-error").empty(),b=!0,a=$("#name").val().trim(),a===""&&($("#name-error").text("Name is required."),b=!1),this.accounts().length===0&&($("#unix-users-error").text("At least one user account is required."),b=!1),b},f.prototype.accounts=function(){var a,b,c,d,e;a=$("#unix-users").val().split(","),e=[];for(c=0,d=a.length;c<d;c++)b=a[c],b.trim().length>0&&e.push(b.trim());return e},f.prototype.save=function(){var a,b;return this.validateForm()?(b=$("#users :checked").map(function(){return $(this).val()}).get(),a={name:$("#name").val(),code:$("#syntax").val(),accounts:this.accounts(),users:b},$("#id").val().length>0&&(a.id=$("#id").val()),this.api.save(c,a,__bind(function(a){var b;return new Notification("Service saved successfully"),a.size=$("#members").length,$("#id").val(a.id),b=$("#services li[data-id='"+a.id+"']"),b.length===0?(b=this.serviceNode(a),this.selectService(b)):$(".text",b).text(a.name)},this)),!1):!1},f.prototype.drawBlankSlate=function(){return $("#beta").empty(),$('<form id="blank-slate">\n <p>\n Services are dynamically updated groups of systems based on\n criteria you define. Send a command to the service and it runs\n on every system in the group.\n </p>\n <input type="submit" id="blank-slate-add" value="Add Service"/>\n</form>').appendTo("#beta"),this.api.user.permissions.services||$("#blank-slate-add").remove(),$("#blank-slate").submit(__bind(function(){return this.drawEditor(),!1},this))},f.prototype.draw=function(){var a;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","services-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Services <div id="search-services-icon"></div></h2>\n <div id="search-services-form"></div>\n <ul id="services" class="selectable scroll y-fill"></ul>\n <div id="alpha-controls" class="controls">\n <div id="add-service"></div>\n <div id="remove-service"></div>\n </div>\n <form id="remove-service-form" class="overlay" style="display:none;">\n <h2>Remove Service</h2>\n <p id="remove-service-msg">Select a service in the list above to remove.</p>\n <fieldset class="buttons" style="display:none;">\n <input id="remove-service-cancel" type="button" value="Cancel"/>\n <input id="remove-service-ok" type="submit" value="Remove"/>\n </fieldset>\n </form>\n</div>\n<div id="beta" class="primary column x-fill y-fill"></div>\n<div id="charlie" class="sidebar column y-fill">\n <h2>Operators</h2>\n <ul id="operators"></ul>\n <h2>Attributes <div id="search-attributes-icon"></div></h2>\n <div id="search-attributes-form"></div>\n <ul id="attributes" class="y-fill scroll"></ul>\n</div>').appendTo("#container"),new Button("#add-service",ICONS.plus),new Button("#remove-service",ICONS.minus),this.api.user.permissions.services||$("#alpha-controls div").remove(),this.drawBlankSlate(),$("#add-service").click(__bind(function(){return this.drawEditor()},this)),$("#remove-service").click(__bind(function(){return this.toggleForm("#remove-service-form")},this)),$("#remove-service-cancel").click(__bind(function(){return this.toggleForm("#remove-service-form")},this)),$("#remove-service-form").submit(__bind(function(){return this.deleteService()},this)),this.operators(),this.findServices(),this.findAttributes(),this.findUsers(),$("#container").show(),this.layout=this.resize(),a=__bind(function(){return this.layout.resize(),this.layout.resize()},this),new Filter({list:"#services",icon:"#search-services-icon",form:"#search-services-form",attrs:["data-name"],open:a,close:a}),new Filter({list:"#attributes",icon:"#search-attributes-icon",form:"#search-attributes-form",attrs:["data-name"],open:a,close:a})},f.prototype.drawEditor=function(a){if(!this.pageVisible())return;return a||(this.selectedService=null,$("#services li").removeClass("selected")),$("#beta").empty(),$('<form id="editor-form" class="sections y-fill scroll">\n <input id="id" type="hidden"/>\n <div>\n <section>\n <h2>Service</h2>\n <fieldset>\n <label for="name">Name</label>\n <input id="name" type="text"/>\n <p id="name-error" class="error"></p>\n <label for="syntax">Criteria</label>\n <textarea id="syntax" placeholder="fqdn starts with \'www.\' and platform is \'mac_os_x\'"></textarea>\n <p id="syntax-status"></p>\n </fieldset>\n </section>\n <section>\n <h2>Members</h2>\n <fieldset id="service-preview">\n <ul id="members" class="scroll"></ul>\n </fieldset>\n </section>\n <section>\n <h2>Permissions</h2>\n <fieldset>\n <label>Users</label>\n <ul id="users" class="scroll"></ul>\n <label for="unix-users">Unix Accounts</label>\n <input id="unix-users" type="text"/>\n <p id="unix-users-error" class="error"></p>\n <p class="hint">Comma separated user names like: apache, postgres, root, etc.</p>\n </fieldset>\n </section>\n </div>\n</form>\n<form id="editor-buttons">\n <input id="save" type="submit" value="Save"/>\n</form>').appendTo("#beta"),a&&(this.findMembers(a.id),$("#id").val(a.id),$("#name").val(a.name),$("#syntax").val(a.code),$("#unix-users").val(a.accounts.join(", "))),this.users.length>0&&this.drawUsers(),this.layout.resize(),$("#name").focus(),$("#syntax").change(__bind(function(){return this.validateIn()},this)),$("#syntax").keyup(__bind(function(){return this.validateIn()},this)),$("#editor-form").submit(__bind(function(){return this.save()},this)),$("#editor-buttons").submit(__bind(function(){return this.save()},this))},f.prototype.drawUsers=function(){var a,b,c,d,e;if(!this.editorVisible())return;$("#users").empty(),e=this.users;for(c=0,d=e.length;c<d;c++)b=e[c],a=$("<li>\n <input id='user-"+b.jid+"' type='checkbox' value='"+b.jid+"'/>\n <label for='user-"+b.jid+"'>"+b.jid+"</label>\n</li>").appendTo("#users"),b.jid===this.session.bareJid()&&$("input",a).prop("checked",!0);if(this.selectedService)return $('#users input[type="checkbox"]').val(this.selectedService.users)},f.prototype.toggleForm=function(a,b){return a=$(a),$("form.overlay").each(function(){if(this.id!==a.attr("id"))return $(this).hide()}),a.is(":hidden")?(b&&b(),a.fadeIn(100)):a.fadeOut(100,function(){a[0].reset();if(b)return b()})},f.prototype.pageVisible=function(){return $("#services-page").length>0},f.prototype.editorVisible=function(){return $("#services-page #editor-form").length>0},f.prototype.resize=function(){var a,b,c;return a=$("#alpha"),b=$("#beta"),c=$("#charlie"),new Layout(function(){return c.css("left",a.width()+b.width())})},f}();var FilesPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};FilesPage=function(){function d(a){this.session=a,this.api=new Api(this.session),this.uploads=new c({session:this.session,jid:this.api.jid,size:this.size,complete:__bind(function(a){return this.findFile(a.name)},this)})}var a,b,c;return a="http://getvines.com/protocol/files",b="http://getvines.com/protocol/files/labels",d.prototype.findLabels=function(){return $("#labels").empty(),this.api.get(b,{},__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.labelNodeList(b));return f},this))},d.prototype.labelNodeList=function(a){var b,c;return c=a.size===1?"file":"files",b=$('<li data-name="">\n <span class="text"></span>\n <span class="count">'+a.size+" "+c+"</span>\n</li>").appendTo("#labels"),$(".text",b).text(a.name),b.attr("data-name",a.name),b.click(__bind(function(a){return this.selectLabel(a)},this))},d.prototype.selectLabel=function(a){var b;return b=$(a.currentTarget).attr("data-name"),$("#labels li").removeClass("selected"),$(a.currentTarget).addClass("selected"),$("#files").empty(),this.findFiles({label:$(a.currentTarget).attr("data-name")})},d.prototype.findFiles=function(b){return this.api.get(a,b,__bind(function(a){var b,c,d,e,f;e=a.rows,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(this.fileNode(b));return f},this))},d.prototype.findFile=function(b){return this.api.get(a,{name:b},__bind(function(a){return this.fileNode(a)},this))},d.prototype.updateFileNode=function(a){var b,c,d;return b=$("#files li[data-id='"+a.id+"']"),c=this.size(a.size),d=this.date(a.created_at),b.data("file",a),$("h2",b).text(a.name),$(".size",b).text(c),$(".time",b).text(d),b.attr("data-name",a.name),b.attr("data-size",c),b.attr("data-created",d)},d.prototype.fileNode=function(a){var b,c,d,e,f,g;if($("#files li[data-id='"+a.id+"']").length>0){this.updateFileNode(a);return}c=$('<li data-id="'+a.id+'">\n <div class="file-icon">\n <span class="size"></span>\n </div>\n <h2></h2>\n <footer>\n <span class="time"></span>\n <ul class="labels"></ul>\n <form class="add-label">\n <div class="add-label-button"></div>\n <input type="text" placeholder="Label" style="display:none;"/>\n </form>\n </footer>\n <form class="file-form">\n <fieldset>\n <input class="cancel" type="submit" value="Delete"/>\n </fieldset>\n </form>\n</li>').appendTo("#files"),new Button($(".file-icon",c).get(0),ICONS.page2,{scale:1,translation:"-2 0","stroke-width":.1,opacity:1}),new Button($(".add-label-button",c).get(0),ICONS.plus,{translation:"-10 -10",scale:.5}),$("form.file-form",c).submit(__bind(function(){return this.deleteFile(c)},this)),$("form.add-label",c).submit(__bind(function(){return this.addLabel(c)},this)),$(".add-label-button",c).click(function(){return $('form.add-label input[type="text"]',c).show()}),this.updateFileNode(a),f=a.labels,g=[];for(d=0,e=f.length;d<e;d++)b=f[d],g.push(this.labelNode(c,b));return g},d.prototype.labelNode=function(a,b){var c,d;return d=$(".labels",a),c=$('<li data-name="">\n <span class="text"></span>\n <div class="remove"></div>\n</li>').appendTo(d),$(".text",c).text(b),c.attr("data-name",b),new Button($(".remove",c).get(0),ICONS.cross,{translation:"-8 -8",scale:.5}),$(".remove",c).click(__bind(function(){return this.removeLabel(a,c)},this))},d.prototype.addLabel=function(b){var c,d,e,f,g,h,i,j,k;d=$('form.add-label input[type="text"]',b),d.hide(),f=function(){var a,b,c,e;c=d.val().split(/,/),e=[];for(a=0,b=c.length;a<b;a++)g=c[a],g&&e.push(g);return e}(),d.val(""),c=b.data("file");for(h=0,j=f.length;h<j;h++)e=f[h],c.labels.push(e);this.api.save(a,c,function(a){});for(i=0,k=f.length;i<k;i++)e=f[i],this.labelNode(b,e),this.updateLabelCount(e,1);return!1},d.prototype.removeLabel=function(b,c){var d,e,f;return d=b.data("file"),f=c.attr("data-name"),d.labels=function(){var a,b,c,g;c=d.labels,g=[];for(a=0,b=c.length;a<b;a++)e=c[a],e!==f&&g.push(e);return g}(),this.api.save(a,d,function(a){}),c.fadeOut(200,function(){return c.remove()}),this.updateLabelCount(f,-1)},d.prototype.updateLabelCount=function(a,b){var c,d,e;return d=$("#labels li[data-name='"+a+"'] .count"),d.length>0?(c=parseInt(d.text().split(" ")[0])+b,e=c===1?"file":"files",d.text(""+c+" "+e)):this.labelNodeList({name:a,size:1})},d.prototype.deleteFile=function(b){return this.api.remove(a,b.attr("data-id"),__bind(function(a){var c,d,e,f;f=b.data("file").labels;for(d=0,e=f.length;d<e;d++)c=f[d],this.updateLabelCount(c,-1);return b.fadeOut(200,function(){return b.remove()})},this)),!1},d.prototype.date=function(a){var b,c;return a=new Date(a),b="Sun Mon Tue Wed Thu Fri Sat".split(" ")[a.getDay()],c="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ")[a.getMonth()],""+b+", "+a.getDate()+" "+c+", "+a.getFullYear()+" @ "+a.getHours()+":"+a.getMinutes()},d.prototype.size=function(a){var b,c,d,e;return d=a/1024,e=d/1024,c=e/1024,b=function(a){return a<100?a.toFixed(1).replace(".0",""):Math.round(a)},d<1?""+a+" b":e<1?""+b(d)+" k":c<1?""+b(e)+" m":""+b(c)+" g"},d.prototype.draw=function(){var a,b;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","files-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Labels</h2>\n <ul id="labels" class="selectable scroll y-fill"></ul>\n <div id="alpha-controls" class="controls"></div>\n</div>\n<div id="beta" class="primary column x-fill y-fill">\n <h2 id="files-title">Files <div id="search-files-icon"></div></h2>\n <div id="search-files-form"></div>\n <ul id="files" class="scroll y-fill"></ul>\n</div>\n<div id="charlie" class="sidebar column y-fill">\n <h2>Uploads</h2>\n <div id="upload-dnd" class="float">Drag files here to upload.</div>\n <ul id="uploads" class="scroll y-fill"></ul>\n <div id="charlie-controls" class="controls">\n <form id="file-form">\n <input id="open-file-chooser" type="submit" value="Select files to upload"/>\n <input id="file-chooser" type="file" multiple="true" />\n </form>\n </div>\n</div>').appendTo("#container"),this.api.user.permissions.files?($("#file-chooser").change(__bind(function(a){return this.uploads.queue(a.target.files),$("#file-chooser").val("")},this)),$("#file-form").submit(function(){return $("#file-chooser").click(),!1}),$("#upload-dnd").bind("dragenter",function(a){return a.stopPropagation(),a.preventDefault(),$("#upload-dnd").css("color","#444")}),$("#upload-dnd").bind("dragleave",function(a){return $("#upload-dnd").css("color","#ababab")}),$("#upload-dnd").bind("dragover",function(a){return a.stopPropagation(),a.preventDefault()}),$("#upload-dnd").bind("drop",__bind(function(a){return a.stopPropagation(),a.preventDefault(),$("#upload-dnd").css("color","#ababab"),this.uploads.queue(a.originalEvent.dataTransfer.files)},this))):($("#upload-dnd").text("Your account cannot upload files."),$("#file-form").remove()),this.findLabels(),this.findFiles(),$("#container").show(),b=this.resize(),a=function(){return b.resize(),b.resize()},new Filter({list:"#files",icon:"#search-files-icon",form:"#search-files-form",attrs:["data-name","data-created"],open:a,close:a})},d.prototype.resize=function(){var a,b,c,d,e;return a=$("#alpha"),b=$("#beta"),c=$("#charlie"),e=$("#uploads"),d=$("#upload-dnd"),new Layout(function(){return c.css("left",a.width()+b.width()),d.height(e.height()),d.css("line-height",e.height()+"px")})},c=function(){function a(a){this.session=a.session,this.serviceJid=a.jid,this.size=a.size,this.complete=a.complete,this.uploads=[],this.sending=null}return a.prototype.queue=function(a){var b,c,d;for(c=0,d=a.length;c<d;c++)b=a[c],this.find(b)||this.add(b);return this.process()},a.prototype.add=function(a){var b,c;return c=this.node(a),b=$(".meter",c),this.uploads.push(new Transfer({to:this.serviceJid(),file:a,session:this.session,progress:function(a){return b.css("width",a+"%")},complete:__bind(function(){return this.remove(a),this.complete&&this.complete(a),a.name===this.sending.name&&(this.sending=null),this.process()},this)}))},a.prototype.process=function(){var a;if(this.sending)return;return(a=this.uploads[0])?(this.sending=a.file,a.start()):this.sending=null},a.prototype.find=function(a){var b;return function(){var c,d,e,f;e=this.uploads,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],b.file.name===a.name&&f.push(b);return f}.call(this).shift()},a.prototype.remove=function(a){var b,c;return this.uploads=function(){var b,d,e,f;e=this.uploads,f=[];for(b=0,d=e.length;b<d;b++)c=e[b],c.file.name!==a.name&&f.push(c);return f}.call(this),b=$("#uploads li[data-file='"+a.name+"']"),b.fadeOut(200,function(){return b.remove()})},a.prototype.node=function(a){var b;return b=$('<li data-file="" style="display:none;">\n <form class="inset">\n <h2></h2>\n <div class="progress">\n <div class="meter"></div>\n <span class="text">'+this.size(a.size)+'</span>\n <div class="cancel"></div>\n </div>\n </form>\n</li>').appendTo("#uploads"),b.fadeIn(200),$("h2",b).text(a.name),b.attr("data-file",a.name),new Button($(".cancel",b).get(0),ICONS.cross,{translation:"-8 -8",scale:.5}),$(".cancel",b).click(__bind(function(){return this.cancel(a)},this)),b},a.prototype.cancel=function(a){var b;if(b=this.find(a))return b.stop()},a}(),d}();var SetupPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};SetupPage=function(){function d(a){this.session=a,this.api=new Api(this.session),this.layout=null,this.selected=null,this.services=[],this.users=[]}var a,b,c;return a="http://getvines.com/protocol/services",b="http://getvines.com/protocol/systems",c="http://getvines.com/protocol/users",d.prototype.findSystem=function(a){return this.api.get(b,{name:a},__bind(function(a){return this.drawSystemInfo(a)},this))},d.prototype.findServices=function(){return this.api.get(a,{},__bind(function(a){return this.services=a.rows,this.drawServices()},this))},d.prototype.drawServices=function(){var a,b,c,d,e;if($("#setup-page #services").length===0)return;$("#services").empty(),e=this.services;for(c=0,d=e.length;c<d;c++)b=e[c],a=$("<li>\n <input id='service-"+b.id+"' type='checkbox' value='"+b.id+"'/>\n <label for='service-"+b.id+"'></label>\n</li>").appendTo("#services"),$("label",a).text(b.name);this.selected&&$('#services input[type="checkbox"]').val(this.selected.services);if(this.selected&&!this.api.user.permissions.services)return $('#services input[type="checkbox"]').prop("disabled",!0)},d.prototype.findUsers=function(){return this.api.get(c,{},__bind(function(a){return this.users=a.rows,this.drawUsers()},this))},d.prototype.drawUsers=function(){var a,b,c,d,e,f;if($("#setup-page #users").length===0)return;$("#users").empty(),a=$("#systems-nav").hasClass("selected"),e=this.users,f=[];for(c=0,d=e.length;c<d;c++)b=e[c],f.push(b.system===a?this.userNode(b):void 0);return f},d.prototype.userNode=function(a){var b,c;return c=$('<li data-name="" data-jid="'+a.jid+'" id="'+a.jid+'">\n <span class="text"></span>\n <span class="jid">'+a.jid+"</span>\n</li>").appendTo("#users"),b=this.userName(a),$(".text",c).text(b),c.attr("data-name",b),c.click(__bind(function(a){return this.selectUser(a.currentTarget)},this)),c},d.prototype.userName=function(a){return a.name||a.jid.split("@")[0]},d.prototype.selectUser=function(a){var b,d;return b=$(a).attr("data-jid"),d=$(a).attr("data-name"),$("#users li").removeClass("selected"),$(a).addClass("selected"),$("#remove-user-msg").html("Are you sure you want to remove "+("<strong>"+d+"</strong>?")),$("#remove-user-form .buttons").fadeIn(200),this.api.get(c,{jid:b},__bind(function(a){return this.selected=a,a.system?this.drawSystemEditor(a):this.drawUserEditor(a)},this))},d.prototype.removeUser=function(){var a;return this.toggleForm("#remove-user-form"),a=$("#users li[data-jid='"+this.selected.jid+"']"),this.api.remove(c,this.selected.jid,__bind(function(b){return a.fadeOut(200,__bind(function(){var b;return this.users=function(){var a,c,d,e;d=this.users,e=[];for(a=0,c=d.length;a<c;a++)b=d[a],b.jid!==this.selected.jid&&e.push(b);return e}.call(this),a.remove(),this.selected=null,$("#users-nav").hasClass("selected")?this.drawUserBlankSlate
|
2
|
+
():this.drawSystemBlankSlate()},this))},this)),!1},d.prototype.selectTask=function(a){this.selected=null,$("#setup li").removeClass("selected secondary"),$(a.currentTarget).addClass("selected secondary");switch($(a.currentTarget).attr("id")){case"users-nav":return $("#beta-header").text("Users"),this.drawUsers(),this.drawUserBlankSlate(),this.api.user.permissions.users?$("#beta-controls div").show():$("#beta-controls div").hide();case"systems-nav":return $("#beta-header").text("Systems"),this.drawUsers(),this.drawSystemBlankSlate(),this.api.user.permissions.systems?$("#beta-controls div").show():$("#beta-controls div").hide()}},d.prototype.toggleForm=function(a,b){return a=$(a),$("form.overlay").each(function(){if(this.id!==a.attr("id"))return $(this).hide()}),a.is(":hidden")?(b&&b(),a.fadeIn(100)):a.fadeOut(100,function(){a[0].reset();if(b)return b()})},d.prototype.validateUser=function(){var a,b,c,d;$("#user-name-error").empty(),$("#password-error").empty(),d=!0,a=$.trim($("#user-name").val()),b=$.trim($("#password1").val()),c=$.trim($("#password2").val());if(this.selected)c.length>0&&c.length<8&&($("#password-error").text("Password must be at least 8 characters."),d=!1),this.session.bareJid()!==this.selected.jid&&b!==c&&($("#password-error").text("Passwords must match."),d=!1);else{a===""&&($("#user-name-error").text("User name is required."),d=!1),a.match(/[\s"&'\/:<>@]/)&&($("#user-name-error").text("User name contains forbidden characters."),d=!1);if(b.length===0||c.length===0)$("#password-error").text("Password is required."),d=!1;b!==c&&($("#password-error").text("Passwords must match."),d=!1),c.length<8&&($("#password-error").text("Password must be at least 8 characters."),d=!1)}return d},d.prototype.saveUser=function(){var a;return this.validateUser()?(a={jid:$("#jid").val(),username:$("#user-name").val(),name:$("#name").val(),password1:$("#password1").val(),password2:$("#password2").val(),services:$("#services :checked").map(function(){return $(this).val()}).get(),permissions:{systems:$("#perm-systems").prop("checked"),services:$("#perm-services").prop("checked"),files:$("#perm-files").prop("checked"),users:$("#perm-users").prop("checked")}},this.api.save(c,a,__bind(function(a){var b;return new Notification("User saved successfully"),$("#jid").val(a.jid),b=$("#users li[data-jid='"+a.jid+"']"),b.length===0?(this.users.push(a),b=this.userNode(a),this.selectUser(b)):$(".text",b).text(this.userName(a))},this)),!1):!1},d.prototype.validateSystem=function(){var a,b;return $("#user-name-error").empty(),b=!0,a=$.trim($("#user-name").val()),this.selected||(a===""&&($("#user-name-error").text("Hostname is required."),b=!1),a.match(/[\s"&'\/:<>@]/)&&($("#user-name-error").text("Hostname contains forbidden characters."),b=!1)),b},d.prototype.saveSystem=function(){var a;return this.validateSystem()?(a={jid:$("#jid").val(),username:$("#user-name").val(),password1:$("#password1").val(),password2:$("#password1").val(),system:!0},this.api.save(c,a,__bind(function(a){var b;return new Notification("System saved successfully"),$("#jid").val(a.jid),b=$("#users li[data-jid='"+a.jid+"']"),b.length===0?(this.users.push(a),b=this.userNode(a),this.selectUser(b)):$(".text",b).text(a.name)},this)),!1):!1},d.prototype.rand=function(){return Math.floor(Math.random()*16)},d.prototype.token=function(){var a;return function(){var b;b=[];for(a=0;a<=127;a++)b.push(this.rand().toString(16));return b}.call(this).join("")},d.prototype.drawUserBlankSlate=function(){var a;return $("#charlie").empty(),a=this.api.user.permissions.users?"Select a user account to update or add a new user.":"Select a user account to update.",$('<form id="blank-slate">\n <p>'+a+'</p>\n <input type="submit" id="blank-slate-add" value="Add User"/>\n</form>').appendTo("#charlie"),this.api.user.permissions.users||$("#blank-slate-add").remove(),$("#blank-slate").submit(__bind(function(){return this.drawUserEditor(),!1},this))},d.prototype.drawSystemBlankSlate=function(){return $("#charlie").empty(),$('<form id="blank-slate">\n <p>\n Systems need a user account before they can connect and\n authenticate with the chat server.\n </p>\n <input type="submit" id="blank-slate-add" value="Add System"/>\n</form>').appendTo("#charlie"),this.api.user.permissions.systems||$("#blank-slate-add").remove(),$("#blank-slate").submit(__bind(function(){return this.drawSystemEditor(),!1},this))},d.prototype.draw=function(){var a;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","setup-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Setup</h2>\n <ul id="setup" class="selectable scroll y-fill">\n <li id="users-nav" class=\'selected secondary\'>\n <span class="text">Users</span>\n </li>\n <li id="systems-nav">\n <span class="text">Systems</span>\n </li>\n </ul>\n <div id="alpha-controls" class="controls"></div>\n</div>\n<div id="beta" class="sidebar column y-fill">\n <h2><span id="beta-header">Users</span> <div id="search-users-icon"></div></h2>\n <div id="search-users-form"></div>\n <ul id="users" class="selectable scroll y-fill"></ul>\n <form id="remove-user-form" class="overlay" style="display:none;">\n <h2>Remove User</h2>\n <p id="remove-user-msg">Select a user to delete.</p>\n <fieldset class="buttons" style="display:none;">\n <input id="remove-user-cancel" type="button" value="Cancel"/>\n <input id="remove-user-ok" type="submit" value="Remove"/>\n </fieldset>\n </form>\n <div id="beta-controls" class="controls">\n <div id="add-user"></div>\n <div id="remove-user"></div>\n </div>\n</div>\n<div id="charlie" class="primary column x-fill y-fill"></div>').appendTo("#container"),this.drawUserBlankSlate(),$("#setup li").click(__bind(function(a){return this.selectTask(a)},this)),this.findUsers(),this.findServices(),$("#container").show(),this.layout=this.resize(),new Button("#add-user",ICONS.plus),new Button("#remove-user",ICONS.minus),this.api.user.permissions.users||$("#beta-controls div").hide(),this.api.user.permissions.systems||$("#systems-nav").hide(),$("#add-user").click(__bind(function(){return $("#users-nav").hasClass("selected")?this.drawUserEditor():this.drawSystemEditor()},this)),$("#remove-user").click(__bind(function(){return this.toggleForm("#remove-user-form")},this)),$("#remove-user-cancel").click(__bind(function(){return this.toggleForm("#remove-user-form")},this)),$("#remove-user-form").submit(__bind(function(){return this.removeUser()},this)),a=__bind(function(){return this.layout.resize(),this.layout.resize()},this),new Filter({list:"#users",icon:"#search-users-icon",form:"#search-users-form",attrs:["data-jid","data-name"],open:a,close:a})},d.prototype.drawUserEditor=function(a){var b,c,d,e;a||(this.selected=null,$("#users li").removeClass("selected")),$("#charlie").empty(),$('<form id="editor-form" class="sections y-fill scroll">\n <div>\n <section>\n <h2>User</h2>\n <fieldset id="jid-fields">\n <input id="jid" type="hidden" value=""/>\n <label for="name">Real Name</label>\n <input id="name" type="text" maxlength="1024"/>\n </fieldset>\n </section>\n <section>\n <h2>Password</h2>\n <fieldset>\n <label id="password1-label" for="password1">Current Password</label>\n <input id="password1" type="password" maxlength="1024"/>\n <label id="password2-label" for="password2">New Password</label>\n <input id="password2" type="password" maxlength="1024"/>\n <p id="password-error" class="error"></p>\n </fieldset>\n </section>\n <section>\n <h2>Permissions</h2>\n <fieldset>\n <label>Manage</label>\n <ul id="permissions">\n <li>\n <input id="perm-systems" type="checkbox" value="systems"/>\n <label for="perm-systems">Systems</label>\n </li>\n <li>\n <input id="perm-services" type="checkbox" value="services"/>\n <label for="perm-services">Services</label>\n </li>\n <li>\n <input id="perm-users" type="checkbox" value="users"/>\n <label for="perm-users">Users</label>\n </li>\n <li>\n <input id="perm-files" type="checkbox" value="files"/>\n <label for="perm-files">Files</label>\n </li>\n </ul>\n </fieldset>\n </section>\n <section>\n <h2>Services</h2>\n <fieldset>\n <label>Access To</label>\n <ul id="services" class="scroll"></ul>\n </fieldset>\n </section>\n </div>\n</form>\n<form id="editor-buttons">\n <input id="save" type="submit" value="Save"/>\n</form>').appendTo("#charlie");if(a){$("<label>Account Name</label>\n<p>"+a.jid+"</p>").prependTo("#jid-fields"),$("#name").focus(),this.session.bareJid()!==a.jid&&($("#password1-label").text("Password"),$("#password2-label").text("Password Again")),$("#jid").val(a.jid),$("#name").val(a.name),$("#user-name").val(a.jid.split("@")[0]),e="services systems files users".split(" ");for(c=0,d=e.length;c<d;c++)b=e[c],a.permissions[b]&&$("#perm-"+b).prop("checked",!0),this.session.bareJid()===a.jid&&$("#perm-"+b).prop("disabled",!0)}else $('<label for="user-name">User Name</label>\n<input id="user-name" type="text" maxlength="1023"/>\n<p id="user-name-error" class="error"></p>').prependTo("#jid-fields"),$("#password1-label").text("Password"),$("#password2-label").text("Password Again"),$("#user-name").focus();return this.services.length>0&&this.drawServices(),this.layout.resize(),$("#editor-form").submit(__bind(function(){return this.saveUser()},this)),$("#editor-buttons").submit(__bind(function(){return this.saveUser()},this))},d.prototype.drawSystemEditor=function(a){return a||(this.selected=null,$("#users li").removeClass("selected")),$("#charlie").empty(),$('<form id="editor-form" class="sections y-fill scroll">\n <div>\n <section>\n <h2>System</h2>\n <fieldset id="jid-fields">\n <input id="jid" type="hidden" value=""/>\n <label id="password1-label" for="password1">Authentication Token</label>\n <div id="token-container">\n <input id="password1" type="text" readonly placeholder="Press Generate to create a new token"/>\n <input id="new-token" type="button" value="Generate"/>\n </div>\n </fieldset>\n </section>\n <section id="info">\n <h2>Info</h2>\n <fieldset>\n <label>Platform</label>\n <p id="info-platform">-</p>\n <label>Hostname</label>\n <p id="info-fqdn">-</p>\n <label>IP Address</label>\n <p id="info-ip">-</p>\n <label>MAC Address</label>\n <p id="info-mac">-</p>\n </fieldset>\n </section>\n </div>\n</form>\n<form id="editor-buttons">\n <input id="save" type="submit" value="Save"/>\n</form>').appendTo("#charlie"),$("#new-token").click(__bind(function(){return $("#password1").val(this.token())},this)),a&&this.findSystem(a.jid.split("@")[0]),a?($("<label>Account Name</label>\n<p>"+a.jid+"</p>").prependTo("#jid-fields"),$("#jid").val(a.jid),$("#user-name").val(a.jid.split("@")[0])):($('<label for="user-name">Hostname</label>\n<input id="user-name" type="text" maxlength="1023"/>\n<p id="user-name-error" class="error"></p>').prependTo("#jid-fields"),$("#user-name").focus(),$("#password1").val(this.token())),this.layout.resize(),$("#editor-form").submit(__bind(function(){return this.saveSystem()},this)),$("#editor-buttons").submit(__bind(function(){return this.saveSystem()},this))},d.prototype.drawSystemInfo=function(a){return $("#info-platform").text(a.platform),$("#info-fqdn").text(a.fqdn),$("#info-ip").text(a.ipaddress),$("#info-mac").text(a.macaddress)},d.prototype.resize=function(){var a,b,c;return a=$("#alpha"),b=$("#beta"),c=$("#charlie"),new Layout(function(){return c.css("left",a.outerWidth()+b.outerWidth())})},d}(),$(function(){var a,b,c,d,e,f;f=new Session,d=new NavBar(f),d.draw(),a={Systems:ICONS.commandline,Services:ICONS.magic,Files:ICONS.page2,Setup:ICONS.gear2,Logout:ICONS.power};for(c in a)b=a[c],d.addButton(c,b);return e={"/systems":new SystemsPage(f),"/services":new ServicesPage(f),"/files":new FilesPage(f),"/setup":new SetupPage(f),"/logout":new LogoutPage(f),"default":new LoginPage(f,"/systems/")},(new Router(e)).draw(),d.select($("#nav-link-systems").parent())})
|