volt 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -2
  3. data/Readme.md +97 -56
  4. data/VERSION +1 -1
  5. data/app/volt/assets/js/sockjs-0.3.4.min.js +27 -0
  6. data/app/volt/assets/js/vertxbus.js +216 -0
  7. data/app/volt/tasks/live_query/live_query.rb +5 -5
  8. data/app/volt/tasks/live_query/live_query_pool.rb +1 -1
  9. data/app/volt/tasks/query_tasks.rb +5 -0
  10. data/app/volt/tasks/store_tasks.rb +44 -18
  11. data/docs/WHY.md +10 -0
  12. data/lib/volt/cli.rb +18 -7
  13. data/lib/volt/controllers/model_controller.rb +30 -8
  14. data/lib/volt/extra_core/inflections.rb +63 -0
  15. data/lib/volt/extra_core/inflector/inflections.rb +203 -0
  16. data/lib/volt/extra_core/inflector/methods.rb +63 -0
  17. data/lib/volt/extra_core/inflector.rb +4 -0
  18. data/lib/volt/extra_core/object.rb +9 -0
  19. data/lib/volt/extra_core/string.rb +10 -14
  20. data/lib/volt/models/array_model.rb +45 -27
  21. data/lib/volt/models/cursor.rb +6 -0
  22. data/lib/volt/models/model.rb +127 -12
  23. data/lib/volt/models/model_hash_behaviour.rb +8 -5
  24. data/lib/volt/models/model_helpers.rb +4 -4
  25. data/lib/volt/models/model_state.rb +22 -0
  26. data/lib/volt/models/persistors/array_store.rb +49 -35
  27. data/lib/volt/models/persistors/base.rb +3 -3
  28. data/lib/volt/models/persistors/model_store.rb +17 -6
  29. data/lib/volt/models/persistors/query/query_listener.rb +0 -2
  30. data/lib/volt/models/persistors/store.rb +0 -4
  31. data/lib/volt/models/persistors/store_state.rb +27 -0
  32. data/lib/volt/models/url.rb +2 -2
  33. data/lib/volt/models/validations/errors.rb +0 -0
  34. data/lib/volt/models/validations/length.rb +13 -0
  35. data/lib/volt/models/validations/validations.rb +82 -0
  36. data/lib/volt/models.rb +1 -1
  37. data/lib/volt/page/bindings/attribute_binding.rb +29 -14
  38. data/lib/volt/page/bindings/base_binding.rb +2 -2
  39. data/lib/volt/page/bindings/component_binding.rb +29 -25
  40. data/lib/volt/page/bindings/content_binding.rb +1 -0
  41. data/lib/volt/page/bindings/each_binding.rb +25 -33
  42. data/lib/volt/page/bindings/event_binding.rb +0 -1
  43. data/lib/volt/page/bindings/if_binding.rb +3 -1
  44. data/lib/volt/page/bindings/template_binding.rb +61 -28
  45. data/lib/volt/page/document_events.rb +3 -1
  46. data/lib/volt/page/draw_cycle.rb +22 -0
  47. data/lib/volt/page/page.rb +10 -1
  48. data/lib/volt/page/reactive_template.rb +23 -16
  49. data/lib/volt/page/sub_context.rb +1 -1
  50. data/lib/volt/page/targets/attribute_section.rb +3 -2
  51. data/lib/volt/page/targets/attribute_target.rb +0 -4
  52. data/lib/volt/page/targets/base_section.rb +25 -0
  53. data/lib/volt/page/targets/binding_document/component_node.rb +13 -14
  54. data/lib/volt/page/targets/binding_document/html_node.rb +4 -0
  55. data/lib/volt/page/targets/dom_section.rb +16 -67
  56. data/lib/volt/page/targets/dom_template.rb +99 -0
  57. data/lib/volt/page/targets/helpers/comment_searchers.rb +29 -0
  58. data/lib/volt/page/template_renderer.rb +2 -14
  59. data/lib/volt/reactive/array_extensions.rb +0 -1
  60. data/lib/volt/reactive/event_chain.rb +9 -2
  61. data/lib/volt/reactive/events.rb +44 -37
  62. data/lib/volt/reactive/object_tracking.rb +1 -1
  63. data/lib/volt/reactive/reactive_array.rb +18 -0
  64. data/lib/volt/reactive/reactive_count.rb +108 -0
  65. data/lib/volt/reactive/reactive_generator.rb +44 -0
  66. data/lib/volt/reactive/reactive_value.rb +73 -73
  67. data/lib/volt/reactive/string_extensions.rb +1 -1
  68. data/lib/volt/router/routes.rb +205 -88
  69. data/lib/volt/server/component_handler.rb +3 -1
  70. data/lib/volt/server/html_parser/view_parser.rb +20 -4
  71. data/lib/volt/server/rack/component_paths.rb +13 -10
  72. data/lib/volt/server/rack/index_files.rb +4 -4
  73. data/lib/volt/server/socket_connection_handler.rb +5 -1
  74. data/lib/volt/server.rb +10 -3
  75. data/spec/apps/kitchen_sink/.gitignore +8 -0
  76. data/spec/apps/kitchen_sink/Gemfile +32 -0
  77. data/spec/apps/kitchen_sink/app/home/views/index/index.html +3 -5
  78. data/spec/apps/kitchen_sink/config.ru +4 -0
  79. data/spec/apps/kitchen_sink/public/index.html +2 -2
  80. data/spec/extra_core/inflector_spec.rb +8 -0
  81. data/spec/models/event_chain_spec.rb +18 -0
  82. data/spec/models/model_buffers_spec.rb +9 -0
  83. data/spec/models/model_spec.rb +22 -9
  84. data/spec/models/reactive_array_spec.rb +26 -1
  85. data/spec/models/reactive_call_times_spec.rb +28 -0
  86. data/spec/models/reactive_value_spec.rb +19 -0
  87. data/spec/models/validations_spec.rb +39 -0
  88. data/spec/page/bindings/content_binding_spec.rb +1 -0
  89. data/spec/{templates → page/bindings}/template_binding_spec.rb +54 -0
  90. data/spec/router/routes_spec.rb +156 -8
  91. data/spec/server/html_parser/sandlebars_parser_spec.rb +55 -47
  92. data/spec/server/html_parser/view_parser_spec.rb +3 -0
  93. data/spec/server/rack/asset_files_spec.rb +1 -1
  94. data/spec/spec_helper.rb +25 -11
  95. data/spec/templates/targets/binding_document/component_node_spec.rb +12 -0
  96. data/templates/project/Gemfile.tt +11 -0
  97. data/templates/project/app/home/config/routes.rb +1 -1
  98. data/templates/project/app/home/controllers/index_controller.rb +5 -5
  99. data/templates/project/app/home/views/index/index.html +6 -6
  100. data/volt.gemspec +5 -6
  101. metadata +34 -76
  102. data/app/volt/assets/js/sockjs-0.2.1.min.js +0 -27
  103. data/lib/volt/reactive/object_tracker.rb +0 -107
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ee2e73e30b22aed5bdde21f95777558f38b2922
4
- data.tar.gz: b0a44bf831aff120f0209c2ea8a4ab49190ea06e
3
+ metadata.gz: fac33a348622b758d4f6ccff8d30234a2720d9c5
4
+ data.tar.gz: 427c22c2ebb283980203073ff812323f6c238e41
5
5
  SHA512:
6
- metadata.gz: 0340cad62884b63d9c757754582696aaaf5c66fe06b8263591782944b9af667ed60d33a3acc2a185140d4d0600415fe64237af54f6b1ef0f91aed20062a159b1
7
- data.tar.gz: 379371a5cf9dca4819d648acd08760b9b685d3b5ac73c865397245e2f3dddf1b41954c62896c8f0ec49898af3b1853561939792571dbded97d5aa98e734af485
6
+ metadata.gz: bf61e39ae71ccc6af0eca7f0c04dfe32e80bc91595059ccf8abb46c4a9c1a75d24aab2dcf985fc94d410103164bdf8b708149a0b807bd837ea395167cb654afb
7
+ data.tar.gz: a98c2352510292f41f34960b376519f77753a228630d521ed756613a090cf006f42f011c85898cd1c3a1c6301672d9851bfa27666dd0fcff8f18605e679fabfc
data/Gemfile CHANGED
@@ -3,7 +3,6 @@ source 'http://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  # gem 'rspec', '3.0.0.beta1'
6
- # gem 'nokogiri', :require => false
7
6
  gem 'opal', git: 'https://github.com/opal/opal.git'
8
7
  gem 'opal-jquery', :git => 'https://github.com/opal/opal-jquery.git'
9
8
  gem 'sockjs', git: 'https://github.com/kacperk/sockjs-ruby.git', require: false, platforms: :mri
@@ -34,4 +33,4 @@ group :development do
34
33
  # gem 'guard-rspec'
35
34
  # gem 'opal-rspec', '0.3.0.beta2'#, git: 'https://github.com/adambeynon/opal-rspec.git'
36
35
  # gem 'yard', require: false
37
- end
36
+ end
data/Readme.md CHANGED
@@ -8,28 +8,29 @@
8
8
 
9
9
  # Volt
10
10
 
11
- Volt is a ruby web framework where your ruby code runs on both the server and the client (via [opal](https://github.com/opal/opal).) The dom automatically update as the user interacts with the page. Page state can be stored in the url, if the user hits a url directly, the HTML will first be rendered on the server for faster load times and easier indexing by search engines.
11
+ Volt is a ruby web framework where your ruby code runs on both the server and the client (via [opal](https://github.com/opal/opal).) The DOM automatically update as the user interacts with the page. Page state can be stored in the URL, if the user hits a URL directly, the HTML will first be rendered on the server for faster load times and easier indexing by search engines.
12
12
 
13
13
  Instead of syncing data between the client and server via HTTP, volt uses a persistent connection between the client and server. When data updated on one client, it is updated in the database and any other listening clients. (With almost no setup code needed)
14
14
 
15
- Pages HTML is written in a handlebars like template language. Volt uses data flow/reactive programming to automatically and intellegently propigate changes to the DOM (or anything other code wanting to know when a value updates) When something in the DOM changes, Volt intelligently updates only the nodes that need to be changed.
15
+ Pages HTML is written in a handlebars like template language. Volt uses data flow/reactive programming to automatically and intelligently propagate changes to the DOM (or anything other code wanting to know when a value updates) When something in the DOM changes, Volt intelligently updates only the nodes that need to be changed.
16
16
 
17
17
  See a quick demo video here: [http://www.youtube.com/watch?v=j0vFIRMzarI](http://www.youtube.com/watch?v=j0vFIRMzarI)
18
18
 
19
+
19
20
  ## Goals
20
21
 
21
22
  Volt has the following goals:
22
23
 
23
- 1. Developer happieness
24
+ 1. Developer happiness
24
25
  2. Write once on the client and the server
25
26
  3. Automatic data syncing between client and server
26
27
  4. Apps are built as nested components. Components can be shared (via gems)
27
28
  5. Concurrent. Volt provides tools to simplify concurrency. Component rendering is done in parallel on the server.
28
- 6. Intellegent asset management
29
+ 6. Intelligent asset management
29
30
  7. Secure (shouldn't need to be said, but it does)
30
31
  8. Be fast/light
31
32
  9. Understandable code base
32
- 10. Control Upgradeability
33
+ 10. Control upgradeability
33
34
 
34
35
  # Road Map
35
36
 
@@ -67,7 +68,7 @@ You can access the volt console with:
67
68
  1. [Getting Help](#getting-help)
68
69
  2. [Rendering](#rendering)
69
70
  1. [Reactive Values](#reactive-values)
70
- 1. [ReactiveValue Gotchyas](#reactivevalue-gotchyas)
71
+ 1. [ReactiveValue Gotchas](#reactivevalue-gotchas)
71
72
  3. [Views](#views)
72
73
  1. [Bindings](#bindings)
73
74
  1. [Content Binding](#content-binding)
@@ -82,9 +83,10 @@ You can access the volt console with:
82
83
  4. [Automatic Model Conversion](#automatic-model-conversion)
83
84
  5. [Controllers](#controllers)
84
85
  6. [Components](#components)
85
- 1. [Assets](#assets)
86
- 2. [Component Generator](#component-generator)
87
- 3. [Provided Components](#provided-components)
86
+ 1. [Dependencies](#dependencies)
87
+ 2. [Assets](#assets)
88
+ 3. [Component Generator](#component-generator)
89
+ 4. [Provided Components](#provided-components)
88
90
  1. [Notices](#notices)
89
91
  2. [Flash](#flash)
90
92
  7. [Controls](#controls)
@@ -94,7 +96,7 @@ You can access the volt console with:
94
96
 
95
97
  # Getting Help
96
98
 
97
- Volt is still a work in progress, but early feedback is appericiated. Use the following to communicate with the developers, someone will get back to you very quickly:
99
+ Volt is still a work in progress, but early feedback is appreciated. Use the following to communicate with the developers, someone will get back to you very quickly:
98
100
 
99
101
  - **If you need help**: post on [stackoverflow.com](http://www.stackoverflow.com), be sure to tag your question with voltrb
100
102
  - **If you found a bug**: post on [github issues](https://github.com/voltrb/volt/issues)
@@ -111,7 +113,7 @@ When a user interacts with a web page, typically we want to do two things:
111
113
 
112
114
  For example when a user clicks to add a new todo item to a todo list, we might create a JavaScript object to represent the todo item, then add an item to the list's DOM. A lot of work needs to be done to make sure that the JavaScript object and the DOM always stay in sync.
113
115
 
114
- Recently the idea of "reactive programming" has been used to simplify maintaining the DOM. The idea is instead of having event handlers that manage a model (or JavaScript object) and manage the DOM, we have event handlers that manage reactive data models. We describe our DOM layer in a declarative way so that it automatically knows how to render our data models.
116
+ The idea of "reactive programming" has been used to simplify maintaining the DOM. The idea is instead of having event handlers that manage a model (or JavaScript object) and manage the DOM, we have event handlers that manage reactive data models. We describe our DOM layer in a declarative way so that it automatically knows how to render our data models.
115
117
 
116
118
  ## Reactive Value's
117
119
 
@@ -122,9 +124,9 @@ To build bindings, Volt provides the ReactiveValue class. This wraps any object
122
124
  # => @"my object"
123
125
  ```
124
126
 
125
- When .inspect is called on a ReactiveValue (like in the console), an @ is placed infront of the value's inspect string, so you know its reactive.
127
+ When .inspect is called on a ReactiveValue (like in the console), an @ is placed in front of the value's inspect string, so you know its reactive.
126
128
 
127
- When you call a method on a ReactiveValue, you get back a new reactive value that depends on the previous one. It remebers how it was created and you can call .cur on it any time to get its current value, which will be computed based off of the first reactive value. (Keep in mind below that + is a method call, the same as a.+(b) in ruby.)
129
+ When you call a method on a ReactiveValue, you get back a new reactive value that depends on the previous one. It remembers how it was created and you can call .cur on it any time to get its current value, which will be computed based off of the first reactive value. (Keep in mind below that + is a method call, the same as a.+(b) in ruby.)
128
130
 
129
131
  ```ruby
130
132
  a = ReactiveValue.new(1)
@@ -146,7 +148,7 @@ When you call a method on a ReactiveValue, you get back a new reactive value tha
146
148
  # => 7
147
149
  ```
148
150
 
149
- This provides the backbone for reactive programming. We setup computation/flow graphs instead of doing an actual calcuation. Calling .cur (or .inspect, .to_s, etc..) runs the computation and returns the current value at that time, based on all of its dependencies.
151
+ This provides the backbone for reactive programming. We setup computation/flow graphs instead of doing an actual calculation. Calling .cur (or .inspect, .to_s, etc..) runs the computation and returns the current value at that time, based on all of its dependencies.
150
152
 
151
153
  ReactiveValue's also let you setup listeners and trigger events:
152
154
 
@@ -157,7 +159,7 @@ ReactiveValue's also let you setup listeners and trigger events:
157
159
  # => A Changed
158
160
  ```
159
161
 
160
- These events propigate to any reactive value's created off of a reactive value.
162
+ These events propagate to any reactive value's created off of a reactive value.
161
163
 
162
164
  ```ruby
163
165
  a = ReactiveValue.new(1)
@@ -170,7 +172,7 @@ These events propigate to any reactive value's created off of a reactive value.
170
172
 
171
173
  This event flow lets us know when an object has changed, so we can update everything that depended on that object.
172
174
 
173
- Lastly, we can also pass in other reactive value's as arguments to methods on a reactive value. The dependencies will be tracked for both and events will propigate down from both. (Also, note that doing `.cur =` to update the current value triggers a "changed" event.)
175
+ Lastly, we can also pass in other reactive value's as arguments to methods on a reactive value. The dependencies will be tracked for both and events will propagate down from both. (Also, note that doing `.cur =` to update the current value triggers a "changed" event.)
174
176
 
175
177
  ```ruby
176
178
  a = ReactiveValue.new(1)
@@ -190,7 +192,7 @@ Lastly, we can also pass in other reactive value's as arguments to methods on a
190
192
  # => C changed
191
193
  ```
192
194
 
193
- ### ReactiveValue Gotchya's
195
+ ### ReactiveValue Gotcha's
194
196
 
195
197
  There are a few simple things to keep in mind with ReactiveValue's. In order to make them mostly compatible with other ruby objects, a two methods do not return another ReactiveValue.
196
198
 
@@ -248,29 +250,33 @@ Views in Volt are use a templating language similar to handlebars. They can be
248
250
  <:Body>
249
251
  ```
250
252
 
251
- Section headers should start with a capital letter so as not to be confused with [controls](#controls). Section headers do not use close tags. If section headers are not provided, the body section is assumed.
253
+ Section headers should start with a capital letter so as not to be confused with [controls](#controls). Section headers do not use closing tags. If section headers are not provided, the Body section is assumed.
252
254
 
253
255
  Section's help you split up different parts of the same content (title and body usually), but within the same file.
254
256
 
255
257
  ## Bindings
256
258
 
257
- One you understand the basics of ReactiveValue's, we can discuss bindings. In Volt, you code your views in a handlebar's like template language. Volt provides severial bindings, which handle rendering of something for you. Content bindings are anything inbetween { and }
259
+ One you understand the basics of ReactiveValue's, we can discuss bindings. In Volt, you code your views in a handlebar's like template language. Volt provides several bindings, which handle rendering of something for you. Content bindings are anything inbetween { and }
258
260
 
259
261
  ### Content binding
260
262
 
261
263
  The most basic binding is a content binding:
262
264
 
265
+ ```html
263
266
  <p>{some_method}<p>
267
+ ```
264
268
 
265
- The content binding runs the ruby code between { and }, then renders the return value. If the returned value is a ReactiveValue, it will update the value updated whenever a 'changed' event is called.
269
+ The content binding runs the ruby code between { and }, then renders the return value. If the returned value is a ReactiveValue, it will update the value updated whenever a 'changed' event is triggered on the reactive value.
266
270
 
267
271
  ### If binding
268
272
 
269
273
  An if binding lets you provide basic flow control.
270
274
 
275
+ ```html
271
276
  {#if _some_check?}
272
277
  <p>render this</p>
273
278
  {/}
279
+ ```
274
280
 
275
281
  Blocks are closed with a {/}
276
282
 
@@ -278,6 +284,7 @@ When the #if binding is rendered, it will run the ruby code after #if. If the c
278
284
 
279
285
  If bindings can also have #elsif and #else blocks.
280
286
 
287
+ ```html
281
288
  {#if _condition_1?}
282
289
  <p>condition 1 true</p>
283
290
  {#elsif _condition_2?}
@@ -285,22 +292,27 @@ If bindings can also have #elsif and #else blocks.
285
292
  {#else}
286
293
  <p>neither true</p>
287
294
  {/}
295
+ ```
288
296
 
289
297
  ### Each binding
290
298
 
291
299
  For iteration over objects, the each binding is provided.
292
300
 
301
+ ```html
293
302
  {#each _items as item}
294
303
  <p>{item}</p>
295
304
  {/}
305
+ ```
296
306
 
297
307
  Above, if _items was an array, the block would be rendered for each item, setting 'item' to the value of the array element.
298
308
 
299
309
  You can also access the position of the item in the array with the #index method.
300
310
 
311
+ ```html
301
312
  {#each _items as item}
302
313
  <p>{index}. {item}</p>
303
314
  {/}
315
+ ```
304
316
 
305
317
  For the array: ['one', 'two', 'three'] this would print:
306
318
 
@@ -308,23 +320,29 @@ For the array: ['one', 'two', 'three'] this would print:
308
320
  1. two
309
321
  2. three
310
322
 
311
- You can do {index + 1} to correct the numbers.
323
+ You can do {index + 1} to correct the zero offset.
312
324
 
313
- When items are removed or added to the array, the #each binding automatically and intellegently add or removes the items from/to the dom.
325
+ When items are removed or added to the array, the #each binding automatically and intelligently add or removes the items from/to the DOM.
314
326
 
315
327
  ## Attribute Bindings
316
328
 
317
329
  Bindings can also be placed inside of attributes.
318
330
 
331
+ ```html
319
332
  <p class="{#if _is_cool?}cool{/}">Text</p>
333
+ ```
320
334
 
321
335
  There are some special features provided to make for elements work as "two way bindings"
322
336
 
337
+ ```html
323
338
  <input type="text" value="{_name}" />
339
+ ```
324
340
 
325
341
  In the example above, if _name changes, the field will update and if the field is updated, _name will be changed.
326
342
 
343
+ ```html
327
344
  <input type="checkbox" checked="{_checked}" />
345
+ ```
328
346
 
329
347
  If the value of a checked attribute is true, the checkbox will be shown checked. If it is checked/unchecked, the value will be updated to true or false.
330
348
 
@@ -337,14 +355,14 @@ If you have a controller at app/home/controller/index_controller.rb, and a view
337
355
  When you need to use { and } outside of bindings. Anything in a triple mustache will be escaped and not processed as a binding:
338
356
 
339
357
  ```html
340
- {{{ bindings look like: {this} }}}
358
+ {{{ bindings look like: {this} }}}
341
359
  ```
342
360
 
343
361
  # Models
344
362
 
345
- Volt's concept of a model is slightly different from many frameworks where a model is the name for the ORM to the database. In Volt a model is a class where you can store data easily. Where that data stored is not the concern of the model, but the class that created the model. Lets first see how to use a model.
363
+ Volt's concept of a model is slightly different from many frameworks where a model is the name for the ORM to the database. In Volt a model is a class where you can store data easily. Models can be created with a "Persistor", which is responsible for storing the data in the model. Models created without a persistor, simply store the data in the classes instance. Lets first see how to use a model.
346
364
 
347
- Volt comes with many built-in models, one is called 'page'. If you call #page on a controller, you will get access to the model. Models provided by Volt are automatically wrapped in a ReactiveValue.
365
+ Volt comes with many built-in models, one is called 'page'. If you call #page on a controller, you will get access to the model. Models provided by Volt are automatically wrapped in a ReactiveValue so update events can be tracked.
348
366
 
349
367
  ```ruby
350
368
  page._name = 'Ryan'
@@ -352,9 +370,9 @@ Volt comes with many built-in models, one is called 'page'. If you call #page o
352
370
  # => @'Ryan'
353
371
  ```
354
372
 
355
- Models act like a hash that you can access with getters and setters that start with an _ Prefixing with an underscore makes sure we don't accidentally try to call a method that doesn't exist and get back nil. There is no need to define which fields a model has, they act similar to a hash, but with a shorter access and assign syntax.
373
+ Models act like a hash that you can access with getters and setters that start with an _ If an underscore method is called that hasn't yet been assigned, you will get back a "nil model". Prefixing with an underscore makes sure we don't accidentally try to call a method that doesn't exist and get back nil model instead of raising an exception. There is no need to define which fields a model has, they act similar to a hash, but with a different access and assign syntax.
356
374
 
357
- Models also let you nest data:
375
+ Models also let you nest data without creating the intermediate models:
358
376
 
359
377
  ```ruby
360
378
  page._settings._color = 'blue'
@@ -367,7 +385,7 @@ Models also let you nest data:
367
385
 
368
386
  Nested data is automatically setup when assigned. In this case, page._settings is a model that is part of the page model.
369
387
 
370
- You can also append to a model if its not defined yet.
388
+ You can also append to a model if its not defined yet. In Volt models, plural properties are assumed to contain arrays (or more specifically ArrayModels)
371
389
 
372
390
  ```ruby
373
391
  page._items << 'item 1'
@@ -378,18 +396,18 @@ You can also append to a model if its not defined yet.
378
396
  # => @"item 1"
379
397
  ```
380
398
 
381
- An array model will automatically be setup to contain the items appended.
399
+ ArrayModels can be appended to and accessed just like regular arrays.
382
400
 
383
401
  ## Provided Collections
384
402
 
385
- Above I mentioned that Volt comes with many default collection models accessable from a controller. Each stores in a different location.
403
+ Above I mentioned that Volt comes with many default collection models accessible from a controller. Each stores in a different location.
386
404
 
387
405
  | Name | Storage Location |
388
406
  |-----------|---------------------------------------------------------------------------|
389
407
  | page | page provides a temporary store that only lasts for the life of the page. |
390
408
  | store | store syncs the data to the backend database and provides query methods. |
391
409
  | session | values will be stored in a session cookie. |
392
- | params | values will be stored in the params and url. Routes can be setup to change how params are shown in the url. (See routes for more info) |
410
+ | params | values will be stored in the params and URL. Routes can be setup to change how params are shown in the URL. (See routes for more info) |
393
411
  | flash | any strings assigned will be shown at the top of the page and cleared as the user navigates between pages. |
394
412
  | controller| a model for the current controller |
395
413
 
@@ -397,7 +415,7 @@ Above I mentioned that Volt comes with many default collection models accessable
397
415
 
398
416
  ## Reactive Models
399
417
 
400
- Because all models provided by Volt are wrapped in a ReactiveValue, you can register listeners on them and be updated when values change. You can also call methods on their values and get updates when the source's change. Bindings also setup listeners. Models should be the main place you store all data in Volt. While you can use ReactiveValue's manually, most of the time you will want to just use something like the page model.
418
+ Because all models provided by Volt are wrapped in a ReactiveValue, you can register listeners on them and be updated when values change. You can also call methods on their values and get updates when the source's change. Bindings also setup listeners. Models should be the main place you store all data in Volt. While you can use ReactiveValue's manually, most of the time you will want to just use something like the controller model.
401
419
 
402
420
  ## Model Events
403
421
 
@@ -423,7 +441,7 @@ Models trigger events when their data is updated. Currently models emit three e
423
441
 
424
442
  ### Hash -> Model
425
443
 
426
- For convience, when placing a hash inside of another model, it is automatically converted into a model. Models are similar to hashes, but provide support for things like persistance and triggering reactive events.
444
+ For convenience, when placing a hash inside of another model, it is automatically converted into a model. Models are similar to hashes, but provide support for things like persistence and triggering reactive events.
427
445
 
428
446
  ```ruby
429
447
  user = Model.new
@@ -482,7 +500,7 @@ You can get a normal array again by calling .to_a on an ArrayModel.
482
500
 
483
501
  # Controllers
484
502
 
485
- A controller can be any class in Volt, however it is common to have that class inherit from ModelController. A model controller lets you specify a model that the controller works off of. This is a common pattern in Volt. To assign the current model for a controller, simply call the model method passing in one of the following:
503
+ A controller can be any class in Volt, however it is common to have that class inherit from ModelController. A model controller lets you specify a model that the controller works off of. This is a common pattern in Volt. The model for a controller can be assigned by one of the following:
486
504
 
487
505
  1. A symbol representing the name of a provided collection model:
488
506
 
@@ -494,21 +512,25 @@ A controller can be any class in Volt, however it is common to have that class i
494
512
  end
495
513
  ```
496
514
 
497
- This can also be done at anytime on the controller instance:
515
+ 2. Calling self.method = in a method:
498
516
 
499
517
  ```ruby
500
518
  class TodosController < ModelController
501
519
  def initialize
502
- model :page
520
+ self.model = :page
503
521
  end
504
522
  end
505
523
  ```
506
524
 
525
+ In methods, the #model method returns the current model.
526
+
507
527
  See the [provided collections](#provided-collections) section for a list of the available collection models.
508
528
 
509
529
  You can also provide your own object to model.
510
530
 
511
- Now any methods not defined on the TodosController will fall through to the provided model. All views in views/{controller_name} will have this controller as the target for any ruby run in their bindings. This means that calls on self (implicit or with self.) will have the model as their target (after calling through the controller). This lets you add methods to the controller to control how the model is handled.
531
+ In the example above any methods not defined on the TodosController will fall through to the provided model. All views in views/{controller_name} will have this controller as the target for any ruby run in their bindings. This means that calls on self (implicit or with self.) will have the model as their target (after calling through the controller). This lets you add methods to the controller to control how the model is handled, or provide extra methods to the views.
532
+
533
+ Volt is more similar to an MVVM architecture than an MVC architecture. Instead of the controllers passing data off to the views, the controllers are the context for the views. When using a ModelController, the controller automatically forwards all methods it does not handle to the model. This is convienant since you can set a model in the controller and then access its properties directly with methods in bindings. This lets you do something like ```{_name}``` instead of something like ```{@model._name}```
512
534
 
513
535
  Controllers in the app/home component do not need to be namespaced, all other components should namespace controllers like so:
514
536
 
@@ -524,9 +546,11 @@ Here "auth" would be the component name.
524
546
 
525
547
  # Components
526
548
 
527
- Apps are made up of Components. Each folder under app/ is a component. When you visit a route, it loads all of the files in the component on the front end, so new pages within the component can be rendered on the front end. If a url is visited that routes to a different component, the request will be loaded as a normal page load and all of that components files will be loaded. You can think of components as the "reload boundry" between sections of your app.
549
+ Apps are made up of Components. Each folder under app/ is a component. When you visit a route, it loads all of the files in the component on the front end, so new pages within the component can be rendered without a new http request. If a URL is visited that routes to a different component, the request will be loaded as a normal page load and all of that components files will be loaded. You can think of components as the "reload boundary" between sections of your app.
528
550
 
529
- You can also use controls (see below) from one component in another. To do this, you must require the component from the component you wish to use them. This can be done in the ```config/dependencies.rb``` file. Just put
551
+ ## Dependencies
552
+
553
+ You can also use controls (see below) from one component in another. To do this, you must require the component from the component you wish to use them in. This can be done in the ```config/dependencies.rb``` file. Just put
530
554
 
531
555
  ```ruby
532
556
  component 'component_name'
@@ -549,13 +573,15 @@ Note above though that jquery and bootstrap are currently included by default.
549
573
 
550
574
  **Note, asset management is still early, and likely will change quite a bit**
551
575
 
552
- In volt, assets such as JavaScript and CSS (or sass) are automatically included on the page for you. Anything placed inside of a components asset folder is served at /assets (via [Sprockets](https://github.com/sstephenson/sprockets)) Link and script tags are automatically added for each css and js file in assets/css and assets/js respectively. Files are included in their lexical order, so you can add numbers in front if you need to change the load order.
576
+ In volt, assets such as JavaScript and CSS (or sass) are automatically included on the page for you. Anything placed inside of a components asset/js or assets/css folder is served at /assets/{js,css} (via [Sprockets](https://github.com/sstephenson/sprockets)) Link and script tags are automatically added for each css and js file in assets/css and assets/js respectively. Files are included in their lexical order, so you can add numbers in front if you need to change the load order.
553
577
 
554
578
  Any JS/CSS from an included component or component gem will be included as well. By default [bootstrap](http://getbootstrap.com/) is provided by the volt-bootstrap gem.
555
579
 
580
+ **Note: asset bundling is on the TODO list**
581
+
556
582
  ## Component Generator
557
583
 
558
- Components can easily be shared as a gem. Volt provides a scaffold for component gems. In a folder (not in a volt project), simply type: volt gem {component_name} This will create the files needed for the gem. Note that all volt component gems will be prefixed with volt- so they can easily be found by others.
584
+ Components can easily be shared as a gem. Volt provides a scaffold for component gems. In a folder (not in a volt project), simply type: volt gem {component_name} This will create the files needed for the gem. Note that all volt component gems will be prefixed with volt- so they can easily be found by others on github and rubygems.
559
585
 
560
586
  While developing, you can use the component by placing the following in your Gemfile:
561
587
 
@@ -638,9 +664,9 @@ Failing above, Volt will look for a view folder with the control name, and an in
638
664
  Next, all folders under app/ are checked. The view path looked for is {component}/index/index.html with a section of :body.
639
665
 
640
666
  5. gems
641
- Lastly the app folder of all gems that start with volt are checked. They are checekd for a similar path to component.
667
+ Lastly the app folder of all gems that start with volt are checked. They are checked for a similar path to component.
642
668
 
643
- When you create a control, you can also specify multiple parts of the search path in the name. The parts should be seperated by a : Example:
669
+ When you create a control, you can also specify multiple parts of the search path in the name. The parts should be separated by a : Example:
644
670
 
645
671
  ```html
646
672
  <:blog:comments />
@@ -655,28 +681,45 @@ The above would search the following:
655
681
  | blog | comments | index.html | :body |
656
682
  | gems/blog | comments | index.html | :body |
657
683
 
658
- # Context in Controls
684
+ Once the view file for the control or template is found, it will look for a matching controller. If the control is specified as a local template, an empty ModelController will be used. If a controller is found and loaded, a corrosponding "action" method will be called on it if its exists. Action methods default to "index" unless the component or template path has two parts, in which case the last part is the action.
685
+
686
+ # Control Arguments/Attributes
687
+
688
+ Like other html tags, controls can be passed attributes. These are then converted into a hash and passed as the first argument to the initialize method on the controller. The standard ModelController's initialize will then assign each key/value in the attributes hash as instance values. This makes it easy to access attributes passed in.
689
+
690
+ ```html
691
+
692
+ <:Body>
693
+
694
+ <ul>
695
+ {#each _todos as todo}
696
+ <:todo name="{todo._name}" />
697
+ {/}
698
+ </ul>
699
+
700
+ <:Todo>
701
+ <li>{@name}</li>
659
702
 
660
- Controls that render without a provided controller can access the context they were inserted in with the ```.parent``` method. Most of the time you want to pass in any data that will be used. But for things like calling methods on the parent controller, using ```.parent.some_method``` can be useful.
703
+ ```
661
704
 
662
705
 
663
706
  # Routes
664
707
 
665
- Routes in Volt are very different from traditional backend frameworks. Since data is synchronized using websockets, routes are mainly used to serialize the state of the application in a pretty way. When a page is first loaded, the url is parsed with the routes and the params model's values are set from the url. Later if the params model is updated, the url is updated based on the routes.
708
+ Routes in Volt are very different from traditional backend frameworks. Since data is synchronized using websockets, routes are mainly used to serialize the state of the application into the url in a pretty way. When a page is first loaded, the URL is parsed with the routes and the params model's values are set from the URL. Later if the params model is updated, the URL is updated based on the routes.
666
709
 
667
- This means that routes in volt have to go both from url to params and params to url. It should also be noted that if a link is clicked and the controller/view to render the new url is within the current component (or an included component), the page will not be reloaded, the url will be updated with the HTML5 history API, and the params hash will reflect the new url. You can use the changes in params to render different views based on the url.
710
+ This means that routes in Volt have to be able to go both from URL to params and params to URL. It should also be noted that if a link is clicked and the controller/view to render the new URL is within the current component (or an included component), the page will not be reloaded, the URL will be updated with the HTML5 history API, and the params hash will reflect the new URL. You can use the changes in params to render different views based on the URL.
668
711
 
669
712
  ## Routes file
670
713
 
671
- Routes are specified on a per-component basis in the config/routes.rb file. Routes simply map from url to params.
714
+ Routes are specified on a per-component basis in the config/routes.rb file. Routes simply map from URL to params.
672
715
 
673
716
  ```ruby
674
717
  get "/todos", _view: 'todos'
675
718
  ```
676
719
 
677
- Routes take two arguments, a path, and a params hash. When a new url is loaded and the path is matched on a route, the params will be set to the params provided for that route.
720
+ Routes take two arguments, a path, and a params hash. When a new URL is loaded and the path is matched on a route, the params will be set to the params provided for that route.
678
721
 
679
- When the params are changed, the url will be set to the path for the route that's params hash matches.
722
+ When the params are changed, the URL will be set to the path for the route that's params hash matches.
680
723
 
681
724
  Route path's can also contain variables similar to bindings.
682
725
 
@@ -684,7 +727,7 @@ Route path's can also contain variables similar to bindings.
684
727
  get "/todos/{_index}", _view: 'todos'
685
728
  ```
686
729
 
687
- In the case above, if any url matches /todos/*, (where * is anything but a slash), it will be the active route. ```params._view``` would be set to 'todos', and ```params._index``` would be set to the value in the path.
730
+ In the case above, if any URL matches /todos/*, (where * is anything but a slash), it will be the active route. ```params._view``` would be set to 'todos', and ```params._index``` would be set to the value in the path.
688
731
 
689
732
  If ```params._view``` is 'todos' and ```params._index``` is not nil, the route would be matched.
690
733
 
@@ -719,10 +762,9 @@ TODO
719
762
 
720
763
  # Data Store
721
764
 
722
- Volt provides a data store collection on the front-end and the back-end. Unlike the other [collections](#provided-collections), all plural names are assumed to be collections (like an array), and all singluar are assumed to be a model (like a hash).
765
+ Volt provides a data store collection on the front-end and the back-end. In store, all plural names are assumed to be collections (like an array), and all singular are assumed to be a model (like a hash).
723
766
 
724
767
  ```ruby
725
-
726
768
  store._things
727
769
  ```
728
770
 
@@ -735,7 +777,6 @@ store._things
735
777
  | loaded | yes | data is loaded and there is an event bound |
736
778
  | dirty | no | data was either accessed without binding an event, or an event was bound, but later unbound. |
737
779
 
780
+ # Contributing
738
781
 
739
- # Why Volt is Awesome
740
-
741
- - only the relevant dom is updated. There is no match and patch algorithm to update from strings like other frameworks, all associations are tracked through our reactive values, so we know exactly what needs to be updated without the need to generate any extra html. This has a few advantages, namely that things like input fields are retained, so any properties (focus, tab position, etc...) are also retained.
782
+ You want to contribute? Great! Thanks for being awesome! At the moment, we have a big internal todo list, hop on #voltrb on freenode (irc) so we don't duplicate work. Pull requests are always welcome, but asking about helping on IRC should save some duplication.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.1
1
+ 0.7.2
@@ -0,0 +1,27 @@
1
+ /* SockJS client, version 0.3.4, http://sockjs.org, MIT License
2
+
3
+ Copyright (c) 2011-2012 VMware, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+ */
23
+
24
+ // JSON2 by Douglas Crockford (minified).
25
+ var JSON;JSON||(JSON={}),function(){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&&typeof i=="object"&&typeof i.toJSON=="function"&&(i=i.toJSON(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c<f;c+=1)h[c]=str(c,i)||"null";e=h.length===0?"[]":gap?"[\n"+gap+h.join(",\n"+gap)+"\n"+g+"]":"["+h.join(",")+"]",gap=g;return e}if(rep&&typeof rep=="object"){f=rep.length;for(c=0;c<f;c+=1)typeof rep[c]=="string"&&(d=rep[c],e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e))}else for(d in i)Object.prototype.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e));e=h.length===0?"{}":gap?"{\n"+gap+h.join(",\n"+gap)+"\n"+g+"}":"{"+h.join(",")+"}",gap=g;return e}}function quote(a){escapable.lastIndex=0;return escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return typeof b=="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function f(a){return a<10?"0"+a:a}"use strict",typeof Date.prototype.toJSON!="function"&&(Date.prototype.toJSON=function(a){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;typeof JSON.stringify!="function"&&(JSON.stringify=function(a,b,c){var d;gap="",indent="";if(typeof c=="number")for(d=0;d<c;d+=1)indent+=" ";else typeof c=="string"&&(indent=c);rep=b;if(!b||typeof b=="function"||typeof b=="object"&&typeof b.length=="number")return str("",{"":a});throw new Error("JSON.stringify")}),typeof JSON.parse!="function"&&(JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver=="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")})}()
26
+
27
+ SockJS=function(){var a=document,b=window,c={},d=function(){};d.prototype.addEventListener=function(a,b){this._listeners||(this._listeners={}),a in this._listeners||(this._listeners[a]=[]);var d=this._listeners[a];c.arrIndexOf(d,b)===-1&&d.push(b);return},d.prototype.removeEventListener=function(a,b){if(!(this._listeners&&a in this._listeners))return;var d=this._listeners[a],e=c.arrIndexOf(d,b);if(e!==-1){d.length>1?this._listeners[a]=d.slice(0,e).concat(d.slice(e+1)):delete this._listeners[a];return}return},d.prototype.dispatchEvent=function(a){var b=a.type,c=Array.prototype.slice.call(arguments,0);this["on"+b]&&this["on"+b].apply(this,c);if(this._listeners&&b in this._listeners)for(var d=0;d<this._listeners[b].length;d++)this._listeners[b][d].apply(this,c)};var e=function(a,b){this.type=a;if(typeof b!="undefined")for(var c in b){if(!b.hasOwnProperty(c))continue;this[c]=b[c]}};e.prototype.toString=function(){var a=[];for(var b in this){if(!this.hasOwnProperty(b))continue;var c=this[b];typeof c=="function"&&(c="[function]"),a.push(b+"="+c)}return"SimpleEvent("+a.join(", ")+")"};var f=function(a){var b=this;b._events=a||[],b._listeners={}};f.prototype.emit=function(a){var b=this;b._verifyType(a);if(b._nuked)return;var c=Array.prototype.slice.call(arguments,1);b["on"+a]&&b["on"+a].apply(b,c);if(a in b._listeners)for(var d=0;d<b._listeners[a].length;d++)b._listeners[a][d].apply(b,c)},f.prototype.on=function(a,b){var c=this;c._verifyType(a);if(c._nuked)return;a in c._listeners||(c._listeners[a]=[]),c._listeners[a].push(b)},f.prototype._verifyType=function(a){var b=this;c.arrIndexOf(b._events,a)===-1&&c.log("Event "+JSON.stringify(a)+" not listed "+JSON.stringify(b._events)+" in "+b)},f.prototype.nuke=function(){var a=this;a._nuked=!0;for(var b=0;b<a._events.length;b++)delete a[a._events[b]];a._listeners={}};var g="abcdefghijklmnopqrstuvwxyz0123456789_";c.random_string=function(a,b){b=b||g.length;var c,d=[];for(c=0;c<a;c++)d.push(g.substr(Math.floor(Math.random()*b),1));return d.join("")},c.random_number=function(a){return Math.floor(Math.random()*a)},c.random_number_string=function(a){var b=(""+(a-1)).length,d=Array(b+1).join("0");return(d+c.random_number(a)).slice(-b)},c.getOrigin=function(a){a+="/";var b=a.split("/").slice(0,3);return b.join("/")},c.isSameOriginUrl=function(a,c){return c||(c=b.location.href),a.split("/").slice(0,3).join("/")===c.split("/").slice(0,3).join("/")},c.getParentDomain=function(a){if(/^[0-9.]*$/.test(a))return a;if(/^\[/.test(a))return a;if(!/[.]/.test(a))return a;var b=a.split(".").slice(1);return b.join(".")},c.objectExtend=function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a};var h="_jp";c.polluteGlobalNamespace=function(){h in b||(b[h]={})},c.closeFrame=function(a,b){return"c"+JSON.stringify([a,b])},c.userSetCode=function(a){return a===1e3||a>=3e3&&a<=4999},c.countRTO=function(a){var b;return a>100?b=3*a:b=a+200,b},c.log=function(){b.console&&console.log&&console.log.apply&&console.log.apply(console,arguments)},c.bind=function(a,b){return a.bind?a.bind(b):function(){return a.apply(b,arguments)}},c.flatUrl=function(a){return a.indexOf("?")===-1&&a.indexOf("#")===-1},c.amendUrl=function(b){var d=a.location;if(!b)throw new Error("Wrong url for SockJS");if(!c.flatUrl(b))throw new Error("Only basic urls are supported in SockJS");return b.indexOf("//")===0&&(b=d.protocol+b),b.indexOf("/")===0&&(b=d.protocol+"//"+d.host+b),b=b.replace(/[/]+$/,""),b},c.arrIndexOf=function(a,b){for(var c=0;c<a.length;c++)if(a[c]===b)return c;return-1},c.arrSkip=function(a,b){var d=c.arrIndexOf(a,b);if(d===-1)return a.slice();var e=a.slice(0,d);return e.concat(a.slice(d+1))},c.isArray=Array.isArray||function(a){return{}.toString.call(a).indexOf("Array")>=0},c.delay=function(a,b){return typeof a=="function"&&(b=a,a=0),setTimeout(b,a)};var i=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j={"\0":"\\u0000","\x01":"\\u0001","\x02":"\\u0002","\x03":"\\u0003","\x04":"\\u0004","\x05":"\\u0005","\x06":"\\u0006","\x07":"\\u0007","\b":"\\b","\t":"\\t","\n":"\\n","\x0b":"\\u000b","\f":"\\f","\r":"\\r","\x0e":"\\u000e","\x0f":"\\u000f","\x10":"\\u0010","\x11":"\\u0011","\x12":"\\u0012","\x13":"\\u0013","\x14":"\\u0014","\x15":"\\u0015","\x16":"\\u0016","\x17":"\\u0017","\x18":"\\u0018","\x19":"\\u0019","\x1a":"\\u001a","\x1b":"\\u001b","\x1c":"\\u001c","\x1d":"\\u001d","\x1e":"\\u001e","\x1f":"\\u001f",'"':'\\"',"\\":"\\\\","\x7f":"\\u007f","\x80":"\\u0080","\x81":"\\u0081","\x82":"\\u0082","\x83":"\\u0083","\x84":"\\u0084","\x85":"\\u0085","\x86":"\\u0086","\x87":"\\u0087","\x88":"\\u0088","\x89":"\\u0089","\x8a":"\\u008a","\x8b":"\\u008b","\x8c":"\\u008c","\x8d":"\\u008d","\x8e":"\\u008e","\x8f":"\\u008f","\x90":"\\u0090","\x91":"\\u0091","\x92":"\\u0092","\x93":"\\u0093","\x94":"\\u0094","\x95":"\\u0095","\x96":"\\u0096","\x97":"\\u0097","\x98":"\\u0098","\x99":"\\u0099","\x9a":"\\u009a","\x9b":"\\u009b","\x9c":"\\u009c","\x9d":"\\u009d","\x9e":"\\u009e","\x9f":"\\u009f","\xad":"\\u00ad","\u0600":"\\u0600","\u0601":"\\u0601","\u0602":"\\u0602","\u0603":"\\u0603","\u0604":"\\u0604","\u070f":"\\u070f","\u17b4":"\\u17b4","\u17b5":"\\u17b5","\u200c":"\\u200c","\u200d":"\\u200d","\u200e":"\\u200e","\u200f":"\\u200f","\u2028":"\\u2028","\u2029":"\\u2029","\u202a":"\\u202a","\u202b":"\\u202b","\u202c":"\\u202c","\u202d":"\\u202d","\u202e":"\\u202e","\u202f":"\\u202f","\u2060":"\\u2060","\u2061":"\\u2061","\u2062":"\\u2062","\u2063":"\\u2063","\u2064":"\\u2064","\u2065":"\\u2065","\u2066":"\\u2066","\u2067":"\\u2067","\u2068":"\\u2068","\u2069":"\\u2069","\u206a":"\\u206a","\u206b":"\\u206b","\u206c":"\\u206c","\u206d":"\\u206d","\u206e":"\\u206e","\u206f":"\\u206f","\ufeff":"\\ufeff","\ufff0":"\\ufff0","\ufff1":"\\ufff1","\ufff2":"\\ufff2","\ufff3":"\\ufff3","\ufff4":"\\ufff4","\ufff5":"\\ufff5","\ufff6":"\\ufff6","\ufff7":"\\ufff7","\ufff8":"\\ufff8","\ufff9":"\\ufff9","\ufffa":"\\ufffa","\ufffb":"\\ufffb","\ufffc":"\\ufffc","\ufffd":"\\ufffd","\ufffe":"\\ufffe","\uffff":"\\uffff"},k=/[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f80-\u0f83\u0f93\u0f9d\u0fa2\u0fa7\u0fac\u0fb9\u1939-\u193a\u1a17\u1b6b\u1cda-\u1cdb\u1dc0-\u1dcf\u1dfc\u1dfe\u1f71\u1f73\u1f75\u1f77\u1f79\u1f7b\u1f7d\u1fbb\u1fbe\u1fc9\u1fcb\u1fd3\u1fdb\u1fe3\u1feb\u1fee-\u1fef\u1ff9\u1ffb\u1ffd\u2000-\u2001\u20d0-\u20d1\u20d4-\u20d7\u20e7-\u20e9\u2126\u212a-\u212b\u2329-\u232a\u2adc\u302b-\u302c\uaab2-\uaab3\uf900-\ufa0d\ufa10\ufa12\ufa15-\ufa1e\ufa20\ufa22\ufa25-\ufa26\ufa2a-\ufa2d\ufa30-\ufa6d\ufa70-\ufad9\ufb1d\ufb1f\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4e\ufff0-\uffff]/g,l,m=JSON&&JSON.stringify||function(a){return i.lastIndex=0,i.test(a)&&(a=a.replace(i,function(a){return j[a]})),'"'+a+'"'},n=function(a){var b,c={},d=[];for(b=0;b<65536;b++)d.push(String.fromCharCode(b));return a.lastIndex=0,d.join("").replace(a,function(a){return c[a]="\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4),""}),a.lastIndex=0,c};c.quote=function(a){var b=m(a);return k.lastIndex=0,k.test(b)?(l||(l=n(k)),b.replace(k,function(a){return l[a]})):b};var o=["websocket","xdr-streaming","xhr-streaming","iframe-eventsource","iframe-htmlfile","xdr-polling","xhr-polling","iframe-xhr-polling","jsonp-polling"];c.probeProtocols=function(){var a={};for(var b=0;b<o.length;b++){var c=o[b];a[c]=y[c]&&y[c].enabled()}return a},c.detectProtocols=function(a,b,c){var d={},e=[];b||(b=o);for(var f=0;f<b.length;f++){var g=b[f];d[g]=a[g]}var h=function(a){var b=a.shift();d[b]?e.push(b):a.length>0&&h(a)};return c.websocket!==!1&&h(["websocket"]),d["xhr-streaming"]&&!c.null_origin?e.push("xhr-streaming"):d["xdr-streaming"]&&!c.cookie_needed&&!c.null_origin?e.push("xdr-streaming"):h(["iframe-eventsource","iframe-htmlfile"]),d["xhr-polling"]&&!c.null_origin?e.push("xhr-polling"):d["xdr-polling"]&&!c.cookie_needed&&!c.null_origin?e.push("xdr-polling"):h(["iframe-xhr-polling","jsonp-polling"]),e};var p="_sockjs_global";c.createHook=function(){var a="a"+c.random_string(8);if(!(p in b)){var d={};b[p]=function(a){return a in d||(d[a]={id:a,del:function(){delete d[a]}}),d[a]}}return b[p](a)},c.attachMessage=function(a){c.attachEvent("message",a)},c.attachEvent=function(c,d){typeof b.addEventListener!="undefined"?b.addEventListener(c,d,!1):(a.attachEvent("on"+c,d),b.attachEvent("on"+c,d))},c.detachMessage=function(a){c.detachEvent("message",a)},c.detachEvent=function(c,d){typeof b.addEventListener!="undefined"?b.removeEventListener(c,d,!1):(a.detachEvent("on"+c,d),b.detachEvent("on"+c,d))};var q={},r=!1,s=function(){for(var a in q)q[a](),delete q[a]},t=function(){if(r)return;r=!0,s()};c.attachEvent("unload",t),c.unload_add=function(a){var b=c.random_string(8);return q[b]=a,r&&c.delay(s),b},c.unload_del=function(a){a in q&&delete q[a]},c.createIframe=function(b,d){var e=a.createElement("iframe"),f,g,h=function(){clearTimeout(f);try{e.onload=null}catch(a){}e.onerror=null},i=function(){e&&(h(),setTimeout(function(){e&&e.parentNode.removeChild(e),e=null},0),c.unload_del(g))},j=function(a){e&&(i(),d(a))},k=function(a,b){try{e&&e.contentWindow&&e.contentWindow.postMessage(a,b)}catch(c){}};return e.src=b,e.style.display="none",e.style.position="absolute",e.onerror=function(){j("onerror")},e.onload=function(){clearTimeout(f),f=setTimeout(function(){j("onload timeout")},2e3)},a.body.appendChild(e),f=setTimeout(function(){j("timeout")},15e3),g=c.unload_add(i),{post:k,cleanup:i,loaded:h}},c.createHtmlfile=function(a,d){var e=new ActiveXObject("htmlfile"),f,g,i,j=function(){clearTimeout(f)},k=function(){e&&(j(),c.unload_del(g),i.parentNode.removeChild(i),i=e=null,CollectGarbage())},l=function(a){e&&(k(),d(a))},m=function(a,b){try{i&&i.contentWindow&&i.contentWindow.postMessage(a,b)}catch(c){}};e.open(),e.write('<html><script>document.domain="'+document.domain+'";'+"</s"+"cript></html>"),e.close(),e.parentWindow[h]=b[h];var n=e.createElement("div");return e.body.appendChild(n),i=e.createElement("iframe"),n.appendChild(i),i.src=a,f=setTimeout(function(){l("timeout")},15e3),g=c.unload_add(k),{post:m,cleanup:k,loaded:j}};var u=function(){};u.prototype=new f(["chunk","finish"]),u.prototype._start=function(a,d,e,f){var g=this;try{g.xhr=new XMLHttpRequest}catch(h){}if(!g.xhr)try{g.xhr=new b.ActiveXObject("Microsoft.XMLHTTP")}catch(h){}if(b.ActiveXObject||b.XDomainRequest)d+=(d.indexOf("?")===-1?"?":"&")+"t="+ +(new Date);g.unload_ref=c.unload_add(function(){g._cleanup(!0)});try{g.xhr.open(a,d,!0)}catch(i){g.emit("finish",0,""),g._cleanup();return}if(!f||!f.no_credentials)g.xhr.withCredentials="true";if(f&&f.headers)for(var j in f.headers)g.xhr.setRequestHeader(j,f.headers[j]);g.xhr.onreadystatechange=function(){if(g.xhr){var a=g.xhr;switch(a.readyState){case 3:try{var b=a.status,c=a.responseText}catch(a){}b===1223&&(b=204),c&&c.length>0&&g.emit("chunk",b,c);break;case 4:var b=a.status;b===1223&&(b=204),g.emit("finish",b,a.responseText),g._cleanup(!1)}}},g.xhr.send(e)},u.prototype._cleanup=function(a){var b=this;if(!b.xhr)return;c.unload_del(b.unload_ref),b.xhr.onreadystatechange=function(){};if(a)try{b.xhr.abort()}catch(d){}b.unload_ref=b.xhr=null},u.prototype.close=function(){var a=this;a.nuke(),a._cleanup(!0)};var v=c.XHRCorsObject=function(){var a=this,b=arguments;c.delay(function(){a._start.apply(a,b)})};v.prototype=new u;var w=c.XHRLocalObject=function(a,b,d){var e=this;c.delay(function(){e._start(a,b,d,{no_credentials:!0})})};w.prototype=new u;var x=c.XDRObject=function(a,b,d){var e=this;c.delay(function(){e._start(a,b,d)})};x.prototype=new f(["chunk","finish"]),x.prototype._start=function(a,b,d){var e=this,f=new XDomainRequest;b+=(b.indexOf("?")===-1?"?":"&")+"t="+ +(new Date);var g=f.ontimeout=f.onerror=function(){e.emit("finish",0,""),e._cleanup(!1)};f.onprogress=function(){e.emit("chunk",200,f.responseText)},f.onload=function(){e.emit("finish",200,f.responseText),e._cleanup(!1)},e.xdr=f,e.unload_ref=c.unload_add(function(){e._cleanup(!0)});try{e.xdr.open(a,b),e.xdr.send(d)}catch(h){g()}},x.prototype._cleanup=function(a){var b=this;if(!b.xdr)return;c.unload_del(b.unload_ref),b.xdr.ontimeout=b.xdr.onerror=b.xdr.onprogress=b.xdr.onload=null;if(a)try{b.xdr.abort()}catch(d){}b.unload_ref=b.xdr=null},x.prototype.close=function(){var a=this;a.nuke(),a._cleanup(!0)},c.isXHRCorsCapable=function(){return b.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest?1:b.XDomainRequest&&a.domain?2:L.enabled()?3:4};var y=function(a,d,e){if(this===b)return new y(a,d,e);var f=this,g;f._options={devel:!1,debug:!1,protocols_whitelist:[],info:undefined,rtt:undefined},e&&c.objectExtend(f._options,e),f._base_url=c.amendUrl(a),f._server=f._options.server||c.random_number_string(1e3),f._options.protocols_whitelist&&f._options.protocols_whitelist.length?g=f._options.protocols_whitelist:(typeof d=="string"&&d.length>0?g=[d]:c.isArray(d)?g=d:g=null,g&&f._debug('Deprecated API: Use "protocols_whitelist" option instead of supplying protocol list as a second parameter to SockJS constructor.')),f._protocols=[],f.protocol=null,f.readyState=y.CONNECTING,f._ir=S(f._base_url),f._ir.onfinish=function(a,b){f._ir=null,a?(f._options.info&&(a=c.objectExtend(a,f._options.info)),f._options.rtt&&(b=f._options.rtt),f._applyInfo(a,b,g),f._didClose()):f._didClose(1002,"Can't connect to server",!0)}};y.prototype=new d,y.version="0.3.4",y.CONNECTING=0,y.OPEN=1,y.CLOSING=2,y.CLOSED=3,y.prototype._debug=function(){this._options.debug&&c.log.apply(c,arguments)},y.prototype._dispatchOpen=function(){var a=this;a.readyState===y.CONNECTING?(a._transport_tref&&(clearTimeout(a._transport_tref),a._transport_tref=null),a.readyState=y.OPEN,a.dispatchEvent(new e("open"))):a._didClose(1006,"Server lost session")},y.prototype._dispatchMessage=function(a){var b=this;if(b.readyState!==y.OPEN)return;b.dispatchEvent(new e("message",{data:a}))},y.prototype._dispatchHeartbeat=function(a){var b=this;if(b.readyState!==y.OPEN)return;b.dispatchEvent(new e("heartbeat",{}))},y.prototype._didClose=function(a,b,d){var f=this;if(f.readyState!==y.CONNECTING&&f.readyState!==y.OPEN&&f.readyState!==y.CLOSING)throw new Error("INVALID_STATE_ERR");f._ir&&(f._ir.nuke(),f._ir=null),f._transport&&(f._transport.doCleanup(),f._transport=null);var g=new e("close",{code:a,reason:b,wasClean:c.userSetCode(a)});if(!c.userSetCode(a)&&f.readyState===y.CONNECTING&&!d){if(f._try_next_protocol(g))return;g=new e("close",{code:2e3,reason:"All transports failed",wasClean:!1,last_event:g})}f.readyState=y.CLOSED,c.delay(function(){f.dispatchEvent(g)})},y.prototype._didMessage=function(a){var b=this,c=a.slice(0,1);switch(c){case"o":b._dispatchOpen();break;case"a":var d=JSON.parse(a.slice(1)||"[]");for(var e=0;e<d.length;e++)b._dispatchMessage(d[e]);break;case"m":var d=JSON.parse(a.slice(1)||"null");b._dispatchMessage(d);break;case"c":var d=JSON.parse(a.slice(1)||"[]");b._didClose(d[0],d[1]);break;case"h":b._dispatchHeartbeat()}},y.prototype._try_next_protocol=function(b){var d=this;d.protocol&&(d._debug("Closed transport:",d.protocol,""+b),d.protocol=null),d._transport_tref&&(clearTimeout(d._transport_tref),d._transport_tref=null);for(;;){var e=d.protocol=d._protocols.shift();if(!e)return!1;if(y[e]&&y[e].need_body===!0&&(!a.body||typeof a.readyState!="undefined"&&a.readyState!=="complete"))return d._protocols.unshift(e),d.protocol="waiting-for-load",c.attachEvent("load",function(){d._try_next_protocol()}),!0;if(!!y[e]&&!!y[e].enabled(d._options)){var f=y[e].roundTrips||1,g=(d._options.rto||0)*f||5e3;d._transport_tref=c.delay(g,function(){d.readyState===y.CONNECTING&&d._didClose(2007,"Transport timeouted")});var h=c.random_string(8),i=d._base_url+"/"+d._server+"/"+h;return d._debug("Opening transport:",e," url:"+i," RTO:"+d._options.rto),d._transport=new y[e](d,i,d._base_url),!0}d._debug("Skipping transport:",e)}},y.prototype.close=function(a,b){var d=this;if(a&&!c.userSetCode(a))throw new Error("INVALID_ACCESS_ERR");return d.readyState!==y.CONNECTING&&d.readyState!==y.OPEN?!1:(d.readyState=y.CLOSING,d._didClose(a||1e3,b||"Normal closure"),!0)},y.prototype.send=function(a){var b=this;if(b.readyState===y.CONNECTING)throw new Error("INVALID_STATE_ERR");return b.readyState===y.OPEN&&b._transport.doSend(c.quote(""+a)),!0},y.prototype._applyInfo=function(b,d,e){var f=this;f._options.info=b,f._options.rtt=d,f._options.rto=c.countRTO(d),f._options.info.null_origin=!a.domain;var g=c.probeProtocols();f._protocols=c.detectProtocols(g,e,b)};var z=y.websocket=function(a,d){var e=this,f=d+"/websocket";f.slice(0,5)==="https"?f="wss"+f.slice(5):f="ws"+f.slice(4),e.ri=a,e.url=f;var g=b.WebSocket||b.MozWebSocket;e.ws=new g(e.url),e.ws.onmessage=function(a){e.ri._didMessage(a.data)},e.unload_ref=c.unload_add(function(){e.ws.close()}),e.ws.onclose=function(){e.ri._didMessage(c.closeFrame(1006,"WebSocket connection broken"))}};z.prototype.doSend=function(a){this.ws.send("["+a+"]")},z.prototype.doCleanup=function(){var a=this,b=a.ws;b&&(b.onmessage=b.onclose=null,b.close(),c.unload_del(a.unload_ref),a.unload_ref=a.ri=a.ws=null)},z.enabled=function(){return!!b.WebSocket||!!b.MozWebSocket},z.roundTrips=2;var A=function(){};A.prototype.send_constructor=function(a){var b=this;b.send_buffer=[],b.sender=a},A.prototype.doSend=function(a){var b=this;b.send_buffer.push(a),b.send_stop||b.send_schedule()},A.prototype.send_schedule_wait=function(){var a=this,b;a.send_stop=function(){a.send_stop=null,clearTimeout(b)},b=c.delay(25,function(){a.send_stop=null,a.send_schedule()})},A.prototype.send_schedule=function(){var a=this;if(a.send_buffer.length>0){var b="["+a.send_buffer.join(",")+"]";a.send_stop=a.sender(a.trans_url,b,function(b,c){a.send_stop=null,b===!1?a.ri._didClose(1006,"Sending error "+c):a.send_schedule_wait()}),a.send_buffer=[]}},A.prototype.send_destructor=function(){var a=this;a._send_stop&&a._send_stop(),a._send_stop=null};var B=function(b,d,e){var f=this;if(!("_send_form"in f)){var g=f._send_form=a.createElement("form"),h=f._send_area=a.createElement("textarea");h.name="d",g.style.display="none",g.style.position="absolute",g.method="POST",g.enctype="application/x-www-form-urlencoded",g.acceptCharset="UTF-8",g.appendChild(h),a.body.appendChild(g)}var g=f._send_form,h=f._send_area,i="a"+c.random_string(8);g.target=i,g.action=b+"/jsonp_send?i="+i;var j;try{j=a.createElement('<iframe name="'+i+'">')}catch(k){j=a.createElement("iframe"),j.name=i}j.id=i,g.appendChild(j),j.style.display="none";try{h.value=d}catch(l){c.log("Your browser is seriously broken. Go home! "+l.message)}g.submit();var m=function(a){if(!j.onerror)return;j.onreadystatechange=j.onerror=j.onload=null,c.delay(500,function(){j.parentNode.removeChild(j),j=null}),h.value="",e(!0)};return j.onerror=j.onload=m,j.onreadystatechange=function(a){j.readyState=="complete"&&m()},m},C=function(a){return function(b,c,d){var e=new a("POST",b+"/xhr_send",c);return e.onfinish=function(a,b){d(a===200||a===204,"http status "+a)},function(a){d(!1,a)}}},D=function(b,d){var e,f=a.createElement("script"),g,h=function(a){g&&(g.parentNode.removeChild(g),g=null),f&&(clearTimeout(e),f.parentNode.removeChild(f),f.onreadystatechange=f.onerror=f.onload=f.onclick=null,f=null,d(a),d=null)},i=!1,j=null;f.id="a"+c.random_string(8),f.src=b,f.type="text/javascript",f.charset="UTF-8",f.onerror=function(a){j||(j=setTimeout(function(){i||h(c.closeFrame(1006,"JSONP script loaded abnormally (onerror)"))},1e3))},f.onload=function(a){h(c.closeFrame(1006,"JSONP script loaded abnormally (onload)"))},f.onreadystatechange=function(a){if(/loaded|closed/.test(f.readyState)){if(f&&f.htmlFor&&f.onclick){i=!0;try{f.onclick()}catch(b){}}f&&h(c.closeFrame(1006,"JSONP script loaded abnormally (onreadystatechange)"))}};if(typeof f.async=="undefined"&&a.attachEvent)if(!/opera/i.test(navigator.userAgent)){try{f.htmlFor=f.id,f.event="onclick"}catch(k){}f.async=!0}else g=a.createElement("script"),g.text="try{var a = document.getElementById('"+f.id+"'); if(a)a.onerror();}catch(x){};",f.async=g.async=!1;typeof f.async!="undefined"&&(f.async=!0),e=setTimeout(function(){h(c.closeFrame(1006,"JSONP script loaded abnormally (timeout)"))},35e3);var l=a.getElementsByTagName("head")[0];return l.insertBefore(f,l.firstChild),g&&l.insertBefore(g,l.firstChild),h},E=y["jsonp-polling"]=function(a,b){c.polluteGlobalNamespace();var d=this;d.ri=a,d.trans_url=b,d.send_constructor(B),d._schedule_recv()};E.prototype=new A,E.prototype._schedule_recv=function(){var a=this,b=function(b){a._recv_stop=null,b&&(a._is_closing||a.ri._didMessage(b)),a._is_closing||a._schedule_recv()};a._recv_stop=F(a.trans_url+"/jsonp",D,b)},E.enabled=function(){return!0},E.need_body=!0,E.prototype.doCleanup=function(){var a=this;a._is_closing=!0,a._recv_stop&&a._recv_stop(),a.ri=a._recv_stop=null,a.send_destructor()};var F=function(a,d,e){var f="a"+c.random_string(6),g=a+"?c="+escape(h+"."+f),i=0,j=function(a){switch(i){case 0:delete b[h][f],e(a);break;case 1:e(a),i=2;break;case 2:delete b[h][f]}},k=d(g,j);b[h][f]=k;var l=function(){b[h][f]&&(i=1,b[h][f](c.closeFrame(1e3,"JSONP user aborted read")))};return l},G=function(){};G.prototype=new A,G.prototype.run=function(a,b,c,d,e){var f=this;f.ri=a,f.trans_url=b,f.send_constructor(C(e)),f.poll=new $(a,d,b+c,e)},G.prototype.doCleanup=function(){var a=this;a.poll&&(a.poll.abort(),a.poll=null)};var H=y["xhr-streaming"]=function(a,b){this.run(a,b,"/xhr_streaming",bd,c.XHRCorsObject)};H.prototype=new G,H.enabled=function(){return b.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest&&!/opera/i.test(navigator.userAgent)},H.roundTrips=2,H.need_body=!0;var I=y["xdr-streaming"]=function(a,b){this.run(a,b,"/xhr_streaming",bd,c.XDRObject)};I.prototype=new G,I.enabled=function(){return!!b.XDomainRequest},I.roundTrips=2;var J=y["xhr-polling"]=function(a,b){this.run(a,b,"/xhr",bd,c.XHRCorsObject)};J.prototype=new G,J.enabled=H.enabled,J.roundTrips=2;var K=y["xdr-polling"]=function(a,b){this.run(a,b,"/xhr",bd,c.XDRObject)};K.prototype=new G,K.enabled=I.enabled,K.roundTrips=2;var L=function(){};L.prototype.i_constructor=function(a,b,d){var e=this;e.ri=a,e.origin=c.getOrigin(d),e.base_url=d,e.trans_url=b;var f=d+"/iframe.html";e.ri._options.devel&&(f+="?t="+ +(new Date)),e.window_id=c.random_string(8),f+="#"+e.window_id,e.iframeObj=c.createIframe(f,function(a){e.ri._didClose(1006,"Unable to load an iframe ("+a+")")}),e.onmessage_cb=c.bind(e.onmessage,e),c.attachMessage(e.onmessage_cb)},L.prototype.doCleanup=function(){var a=this;if(a.iframeObj){c.detachMessage(a.onmessage_cb);try{a.iframeObj.iframe.contentWindow&&a.postMessage("c")}catch(b){}a.iframeObj.cleanup(),a.iframeObj=null,a.onmessage_cb=a.iframeObj=null}},L.prototype.onmessage=function(a){var b=this;if(a.origin!==b.origin)return;var c=a.data.slice(0,8),d=a.data.slice(8,9),e=a.data.slice(9);if(c!==b.window_id)return;switch(d){case"s":b.iframeObj.loaded(),b.postMessage("s",JSON.stringify([y.version,b.protocol,b.trans_url,b.base_url]));break;case"t":b.ri._didMessage(e)}},L.prototype.postMessage=function(a,b){var c=this;c.iframeObj.post(c.window_id+a+(b||""),c.origin)},L.prototype.doSend=function(a){this.postMessage("m",a)},L.enabled=function(){var a=navigator&&navigator.userAgent&&navigator.userAgent.indexOf("Konqueror")!==-1;return(typeof b.postMessage=="function"||typeof b.postMessage=="object")&&!a};var M,N=function(a,d){parent!==b?parent.postMessage(M+a+(d||""),"*"):c.log("Can't postMessage, no parent window.",a,d)},O=function(){};O.prototype._didClose=function(a,b){N("t",c.closeFrame(a,b))},O.prototype._didMessage=function(a){N("t",a)},O.prototype._doSend=function(a){this._transport.doSend(a)},O.prototype._doCleanup=function(){this._transport.doCleanup()},c.parent_origin=undefined,y.bootstrap_iframe=function(){var d;M=a.location.hash.slice(1);var e=function(a){if(a.source!==parent)return;typeof c.parent_origin=="undefined"&&(c.parent_origin=a.origin);if(a.origin!==c.parent_origin)return;var e=a.data.slice(0,8),f=a.data.slice(8,9),g=a.data.slice(9);if(e!==M)return;switch(f){case"s":var h=JSON.parse(g),i=h[0],j=h[1],k=h[2],l=h[3];i!==y.version&&c.log('Incompatibile SockJS! Main site uses: "'+i+'", the iframe:'+' "'+y.version+'".');if(!c.flatUrl(k)||!c.flatUrl(l)){c.log("Only basic urls are supported in SockJS");return}if(!c.isSameOriginUrl(k)||!c.isSameOriginUrl(l)){c.log("Can't connect to different domain from within an iframe. ("+JSON.stringify([b.location.href,k,l])+")");return}d=new O,d._transport=new O[j](d,k,l);break;case"m":d._doSend(g);break;case"c":d&&d._doCleanup(),d=null}};c.attachMessage(e),N("s")};var P=function(a,b){var d=this;c.delay(function(){d.doXhr(a,b)})};P.prototype=new f(["finish"]),P.prototype.doXhr=function(a,b){var d=this,e=(new Date).getTime(),f=new b("GET",a+"/info"),g=c.delay(8e3,function(){f.ontimeout()});f.onfinish=function(a,b){clearTimeout(g),g=null;if(a===200){var c=(new Date).getTime()-e,f=JSON.parse(b);typeof f!="object"&&(f={}),d.emit("finish",f,c)}else d.emit("finish")},f.ontimeout=function(){f.close(),d.emit("finish")}};var Q=function(b){var d=this,e=function(){var a=new L;a.protocol="w-iframe-info-receiver";var c=function(b){if(typeof b=="string"&&b.substr(0,1)==="m"){var c=JSON.parse(b.substr(1)),e=c[0],f=c[1];d.emit("finish",e,f)}else d.emit("finish");a.doCleanup(),a=null},e={_options:{},_didClose:c,_didMessage:c};a.i_constructor(e,b,b)};a.body?e():c.attachEvent("load",e)};Q.prototype=new f(["finish"]);var R=function(){var a=this;c.delay(function(){a.emit("finish",{},2e3)})};R.prototype=new f(["finish"]);var S=function(a){if(c.isSameOriginUrl(a))return new P(a,c.XHRLocalObject);switch(c.isXHRCorsCapable()){case 1:return new P(a,c.XHRLocalObject);case 2:return new P(a,c.XDRObject);case 3:return new Q(a);default:return new R}},T=O["w-iframe-info-receiver"]=function(a,b,d){var e=new P(d,c.XHRLocalObject);e.onfinish=function(b,c){a._didMessage("m"+JSON.stringify([b,c])),a._didClose()}};T.prototype.doCleanup=function(){};var U=y["iframe-eventsource"]=function(){var a=this;a.protocol="w-iframe-eventsource",a.i_constructor.apply(a,arguments)};U.prototype=new L,U.enabled=function(){return"EventSource"in b&&L.enabled()},U.need_body=!0,U.roundTrips=3;var V=O["w-iframe-eventsource"]=function(a,b){this.run(a,b,"/eventsource",_,c.XHRLocalObject)};V.prototype=new G;var W=y["iframe-xhr-polling"]=function(){var a=this;a.protocol="w-iframe-xhr-polling",a.i_constructor.apply(a,arguments)};W.prototype=new L,W.enabled=function(){return b.XMLHttpRequest&&L.enabled()},W.need_body=!0,W.roundTrips=3;var X=O["w-iframe-xhr-polling"]=function(a,b){this.run(a,b,"/xhr",bd,c.XHRLocalObject)};X.prototype=new G;var Y=y["iframe-htmlfile"]=function(){var a=this;a.protocol="w-iframe-htmlfile",a.i_constructor.apply(a,arguments)};Y.prototype=new L,Y.enabled=function(){return L.enabled()},Y.need_body=!0,Y.roundTrips=3;var Z=O["w-iframe-htmlfile"]=function(a,b){this.run(a,b,"/htmlfile",bc,c.XHRLocalObject)};Z.prototype=new G;var $=function(a,b,c,d){var e=this;e.ri=a,e.Receiver=b,e.recv_url=c,e.AjaxObject=d,e._scheduleRecv()};$.prototype._scheduleRecv=function(){var a=this,b=a.poll=new a.Receiver(a.recv_url,a.AjaxObject),c=0;b.onmessage=function(b){c+=1,a.ri._didMessage(b.data)},b.onclose=function(c){a.poll=b=b.onmessage=b.onclose=null,a.poll_is_closing||(c.reason==="permanent"?a.ri._didClose(1006,"Polling error ("+c.reason+")"):a._scheduleRecv())}},$.prototype.abort=function(){var a=this;a.poll_is_closing=!0,a.poll&&a.poll.abort()};var _=function(a){var b=this,d=new EventSource(a);d.onmessage=function(a){b.dispatchEvent(new e("message",{data:unescape(a.data)}))},b.es_close=d.onerror=function(a,f){var g=f?"user":d.readyState!==2?"network":"permanent";b.es_close=d.onmessage=d.onerror=null,d.close(),d=null,c.delay(200,function(){b.dispatchEvent(new e("close",{reason:g}))})}};_.prototype=new d,_.prototype.abort=function(){var a=this;a.es_close&&a.es_close({},!0)};var ba,bb=function(){if(ba===undefined)if("ActiveXObject"in b)try{ba=!!(new ActiveXObject("htmlfile"))}catch(a){}else ba=!1;return ba},bc=function(a){var d=this;c.polluteGlobalNamespace(),d.id="a"+c.random_string(6,26),a+=(a.indexOf("?")===-1?"?":"&")+"c="+escape(h+"."+d.id);var f=bb()?c.createHtmlfile:c.createIframe,g;b[h][d.id]={start:function(){g.loaded()},message:function(a){d.dispatchEvent(new e("message",{data:a}))},stop:function(){d.iframe_close({},"network")}},d.iframe_close=function(a,c){g.cleanup(),d.iframe_close=g=null,delete b[h][d.id],d.dispatchEvent(new e("close",{reason:c}))},g=f(a,function(a){d.iframe_close({},"permanent")})};bc.prototype=new d,bc.prototype.abort=function(){var a=this;a.iframe_close&&a.iframe_close({},"user")};var bd=function(a,b){var c=this,d=0;c.xo=new b("POST",a,null),c.xo.onchunk=function(a,b){if(a!==200)return;for(;;){var f=b.slice(d),g=f.indexOf("\n");if(g===-1)break;d+=g+1;var h=f.slice(0,g);c.dispatchEvent(new e("message",{data:h}))}},c.xo.onfinish=function(a,b){c.xo.onchunk(a,b),c.xo=null;var d=a===200?"network":"permanent";c.dispatchEvent(new e("close",{reason:d}))}};return bd.prototype=new d,bd.prototype.abort=function(){var a=this;a.xo&&(a.xo.close(),a.dispatchEvent(new e("close",{reason:"user"})),a.xo=null)},y.getUtils=function(){return c},y.getIframeTransport=function(){return L},y}(),"_sockjs_onload"in window&&setTimeout(_sockjs_onload,1),typeof define=="function"&&define.amd&&define("sockjs",[],function(){return SockJS})