spontaneous 0.1.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (556) hide show
  1. data/Gemfile +49 -0
  2. data/Gemfile.lock +146 -0
  3. data/LICENSE +0 -0
  4. data/README +0 -0
  5. data/Rakefile +284 -0
  6. data/Readme.markdown +7 -0
  7. data/application/css/add_alias_dialogue.scss +27 -0
  8. data/application/css/definitions.scss +249 -0
  9. data/application/css/developer.scss +9 -0
  10. data/application/css/editing.scss +649 -0
  11. data/application/css/login.scss +91 -0
  12. data/application/css/min/54ee0ed3c7fac7632bd5c020d69e9a2503e0c88c.css +1 -0
  13. data/application/css/min/c256adc144e2bdd0b0539356b04eb62db01e1dc3.css +1 -0
  14. data/application/css/popover.scss +335 -0
  15. data/application/css/schema_error.scss +90 -0
  16. data/application/css/spontaneous.scss +111 -0
  17. data/application/css/unsupported.scss +16 -0
  18. data/application/css/v2.scss +1606 -0
  19. data/application/css/variables.scss +80 -0
  20. data/application/js/add_alias_dialogue.js +59 -0
  21. data/application/js/add_home_dialogue.js +59 -0
  22. data/application/js/ajax.js +99 -0
  23. data/application/js/authentication.js +22 -0
  24. data/application/js/box.js +104 -0
  25. data/application/js/box_container.js +82 -0
  26. data/application/js/compatibility.js +132 -0
  27. data/application/js/conflicted_field_dialogue.js +92 -0
  28. data/application/js/content.js +224 -0
  29. data/application/js/content_area.js +44 -0
  30. data/application/js/dialogue.js +196 -0
  31. data/application/js/dom.js +71 -0
  32. data/application/js/edit_dialogue.js +137 -0
  33. data/application/js/edit_panel.js +232 -0
  34. data/application/js/editing.js +42 -0
  35. data/application/js/entry.js +13 -0
  36. data/application/js/extensions.js +104 -0
  37. data/application/js/field.js +4 -0
  38. data/application/js/field_preview.js +55 -0
  39. data/application/js/field_types/date_field.js +16 -0
  40. data/application/js/field_types/file_field.js +71 -0
  41. data/application/js/field_types/image_field.js +358 -0
  42. data/application/js/field_types/markdown_field.js +656 -0
  43. data/application/js/field_types/string_field.js +185 -0
  44. data/application/js/image.js +72 -0
  45. data/application/js/init.js +34 -0
  46. data/application/js/load.js +4 -0
  47. data/application/js/location.js +157 -0
  48. data/application/js/login.js +53 -0
  49. data/application/js/min/492a209de8ee955fa9c729a765377495001e11b1.js +17 -0
  50. data/application/js/min/80f684d77c940887a1d4a63e3a96102e993baa98.js +88 -0
  51. data/application/js/min/b8abf302a824c35385ff517b34111e1710ff3b37.js +2 -0
  52. data/application/js/min/c7140ec9475e5bf868b901e0621338d7d162358b.js +3 -0
  53. data/application/js/min/f07f2bd6630ee31e1c2288ec223383d8f0658ba6.js +2 -0
  54. data/application/js/page.js +43 -0
  55. data/application/js/page_browser.js +147 -0
  56. data/application/js/page_entry.js +47 -0
  57. data/application/js/popover.js +99 -0
  58. data/application/js/popover_view.js +56 -0
  59. data/application/js/preview.js +64 -0
  60. data/application/js/progress.js +358 -0
  61. data/application/js/properties.js +90 -0
  62. data/application/js/publish.js +187 -0
  63. data/application/js/require.js +129 -0
  64. data/application/js/sharded_upload.js +206 -0
  65. data/application/js/side_bar.js +30 -0
  66. data/application/js/spontaneous.js +6 -0
  67. data/application/js/state.js +64 -0
  68. data/application/js/status_bar.js +47 -0
  69. data/application/js/top_bar.js +368 -0
  70. data/application/js/types.js +98 -0
  71. data/application/js/upload.js +88 -0
  72. data/application/js/upload_manager.js +319 -0
  73. data/application/js/user.js +37 -0
  74. data/application/js/vendor/.DS_Store +0 -0
  75. data/application/js/vendor/JS.Class-2.1.5/CHANGELOG +283 -0
  76. data/application/js/vendor/JS.Class-2.1.5/MIT-LICENSE +30 -0
  77. data/application/js/vendor/JS.Class-2.1.5/README +30 -0
  78. data/application/js/vendor/JS.Class-2.1.5/min/command.js +1 -0
  79. data/application/js/vendor/JS.Class-2.1.5/min/comparable.js +1 -0
  80. data/application/js/vendor/JS.Class-2.1.5/min/constant_scope.js +1 -0
  81. data/application/js/vendor/JS.Class-2.1.5/min/core.js +1 -0
  82. data/application/js/vendor/JS.Class-2.1.5/min/decorator.js +1 -0
  83. data/application/js/vendor/JS.Class-2.1.5/min/enumerable.js +1 -0
  84. data/application/js/vendor/JS.Class-2.1.5/min/forwardable.js +1 -0
  85. data/application/js/vendor/JS.Class-2.1.5/min/hash.js +1 -0
  86. data/application/js/vendor/JS.Class-2.1.5/min/linked_list.js +1 -0
  87. data/application/js/vendor/JS.Class-2.1.5/min/loader.js +1 -0
  88. data/application/js/vendor/JS.Class-2.1.5/min/method_chain.js +1 -0
  89. data/application/js/vendor/JS.Class-2.1.5/min/observable.js +1 -0
  90. data/application/js/vendor/JS.Class-2.1.5/min/package.js +1 -0
  91. data/application/js/vendor/JS.Class-2.1.5/min/proxy.js +1 -0
  92. data/application/js/vendor/JS.Class-2.1.5/min/ruby.js +1 -0
  93. data/application/js/vendor/JS.Class-2.1.5/min/set.js +1 -0
  94. data/application/js/vendor/JS.Class-2.1.5/min/stack_trace.js +1 -0
  95. data/application/js/vendor/JS.Class-2.1.5/min/state.js +1 -0
  96. data/application/js/vendor/JS.Class-2.1.5/min/stdlib.js +16 -0
  97. data/application/js/vendor/JS.Class-2.1.5/src/command.js +93 -0
  98. data/application/js/vendor/JS.Class-2.1.5/src/comparable.js +37 -0
  99. data/application/js/vendor/JS.Class-2.1.5/src/constant_scope.js +48 -0
  100. data/application/js/vendor/JS.Class-2.1.5/src/core.js +1060 -0
  101. data/application/js/vendor/JS.Class-2.1.5/src/decorator.js +50 -0
  102. data/application/js/vendor/JS.Class-2.1.5/src/enumerable.js +505 -0
  103. data/application/js/vendor/JS.Class-2.1.5/src/forwardable.js +22 -0
  104. data/application/js/vendor/JS.Class-2.1.5/src/hash.js +334 -0
  105. data/application/js/vendor/JS.Class-2.1.5/src/linked_list.js +114 -0
  106. data/application/js/vendor/JS.Class-2.1.5/src/loader.js +553 -0
  107. data/application/js/vendor/JS.Class-2.1.5/src/method_chain.js +172 -0
  108. data/application/js/vendor/JS.Class-2.1.5/src/observable.js +55 -0
  109. data/application/js/vendor/JS.Class-2.1.5/src/package.js +472 -0
  110. data/application/js/vendor/JS.Class-2.1.5/src/proxy.js +58 -0
  111. data/application/js/vendor/JS.Class-2.1.5/src/ruby.js +44 -0
  112. data/application/js/vendor/JS.Class-2.1.5/src/set.js +332 -0
  113. data/application/js/vendor/JS.Class-2.1.5/src/stack_trace.js +151 -0
  114. data/application/js/vendor/JS.Class-2.1.5/src/state.js +95 -0
  115. data/application/js/vendor/JS.Class-2.1.5/src/stdlib.js +2612 -0
  116. data/application/js/vendor/crypto-2.3.0-crypto.js +160 -0
  117. data/application/js/vendor/crypto-2.3.0-sha1.js +91 -0
  118. data/application/js/vendor/diff_match_patch.js +2153 -0
  119. data/application/js/vendor/jquery-1.4.2.min.js +154 -0
  120. data/application/js/vendor/jquery-1.4.3.min.js +166 -0
  121. data/application/js/vendor/jquery-1.5.1.min.js +16 -0
  122. data/application/js/vendor/jquery-1.5.1rc1.min.js +24 -0
  123. data/application/js/vendor/jquery-1.6.2.min.js +18 -0
  124. data/application/js/vendor/jquery-ui-1.8.6.custom.min.js +265 -0
  125. data/application/js/vendor/jquery-ui-1.8.9.custom.min.js +415 -0
  126. data/application/js/vendor/jquery-ui-1.8.custom.min.js +106 -0
  127. data/application/js/vendor/jquery.hotkeys-0.7.9.js +248 -0
  128. data/application/js/vendor/jquery.hotkeys-0.7.9.min.js +19 -0
  129. data/application/js/vendor/jsdiff.js +169 -0
  130. data/application/js/views/box_view.js +229 -0
  131. data/application/js/views/page_piece_view.js +45 -0
  132. data/application/js/views/page_view.js +238 -0
  133. data/application/js/views/piece_view.js +178 -0
  134. data/application/js/views.js +110 -0
  135. data/application/static/editing-0-noise.png +0 -0
  136. data/application/static/editing-1-noise.png +0 -0
  137. data/application/static/editing-texture-1.png +0 -0
  138. data/application/static/editing-texture.png +0 -0
  139. data/application/static/editing-toolbar-shadow-bottom.png +0 -0
  140. data/application/static/editing-toolbar-shadow-top.png +0 -0
  141. data/application/static/favicon.ico +0 -0
  142. data/application/static/inner-glow.png +0 -0
  143. data/application/static/item-buttons.png +0 -0
  144. data/application/static/location-arrow.png +0 -0
  145. data/application/static/logo-400px-transparent.png +0 -0
  146. data/application/static/missing.png +0 -0
  147. data/application/static/orange-down-arrow.png +0 -0
  148. data/application/static/page-browser-next.png +0 -0
  149. data/application/static/paper-texture-dark.png +0 -0
  150. data/application/static/px.gif +0 -0
  151. data/application/static/select-arrow-root.png +0 -0
  152. data/application/static/select-arrow.png +0 -0
  153. data/application/static/slot-down-arrow.png +0 -0
  154. data/application/static/splash.png +0 -0
  155. data/application/static/spontaneous.png +0 -0
  156. data/application/static/spot.png +0 -0
  157. data/application/static/spot.svg +40 -0
  158. data/application/static/texture.png +0 -0
  159. data/application/views/index.erubis +46 -0
  160. data/application/views/login.erubis +69 -0
  161. data/application/views/schema_modification_error.html.erb +61 -0
  162. data/application/views/unsupported.erubis +23 -0
  163. data/bin/limit-upload +5 -0
  164. data/bin/spot +10 -0
  165. data/bin/unlimit-upload +3 -0
  166. data/config/nginx.conf +60 -0
  167. data/db/migrations/20100610142136_init.rb +66 -0
  168. data/db/migrations/20101130104334_timestamps.rb +44 -0
  169. data/db/migrations/20101202113205_site_publishing_flags.rb +12 -0
  170. data/db/migrations/20101206124543_aliases.rb +16 -0
  171. data/db/migrations/20110201133550_visibility.rb +27 -0
  172. data/db/migrations/20110209152710_users_and_groups.rb +58 -0
  173. data/db/migrations/20110215133910_boxes.rb +25 -0
  174. data/db/migrations/20110521114145_remove_slots_and_entries.rb +21 -0
  175. data/db/migrations/20110604192145_rename_schema_id_columns.rb +22 -0
  176. data/db/migrations/20110805141925_rename_site_to_state.rb +11 -0
  177. data/lib/cutaneous/context_helper.rb +82 -0
  178. data/lib/cutaneous/first_pass_parser.rb +23 -0
  179. data/lib/cutaneous/first_pass_renderer.rb +18 -0
  180. data/lib/cutaneous/parser_core.rb +18 -0
  181. data/lib/cutaneous/preview_context.rb +31 -0
  182. data/lib/cutaneous/preview_renderer.rb +15 -0
  183. data/lib/cutaneous/publish_context.rb +9 -0
  184. data/lib/cutaneous/renderer.rb +122 -0
  185. data/lib/cutaneous/request_context.rb +8 -0
  186. data/lib/cutaneous/second_pass_parser.rb +23 -0
  187. data/lib/cutaneous/second_pass_renderer.rb +18 -0
  188. data/lib/cutaneous.rb +47 -0
  189. data/lib/sequel/plugins/content_table_inheritance.rb +196 -0
  190. data/lib/sequel/plugins/yajl_serialization.rb +154 -0
  191. data/lib/spontaneous/application/feature.rb +9 -0
  192. data/lib/spontaneous/application/plugin.rb +13 -0
  193. data/lib/spontaneous/application.rb +8 -0
  194. data/lib/spontaneous/box.rb +232 -0
  195. data/lib/spontaneous/box_style.rb +64 -0
  196. data/lib/spontaneous/change.rb +107 -0
  197. data/lib/spontaneous/cli/adapter.rb +13 -0
  198. data/lib/spontaneous/cli/base.rb +184 -0
  199. data/lib/spontaneous/cli/console.rb +0 -0
  200. data/lib/spontaneous/cli/media.rb +13 -0
  201. data/lib/spontaneous/cli/server.rb +50 -0
  202. data/lib/spontaneous/cli/site.rb +46 -0
  203. data/lib/spontaneous/cli/sync.rb +42 -0
  204. data/lib/spontaneous/cli/tasks.rb +9 -0
  205. data/lib/spontaneous/cli.rb +83 -0
  206. data/lib/spontaneous/collections/box_set.rb +56 -0
  207. data/lib/spontaneous/collections/change_set.rb +43 -0
  208. data/lib/spontaneous/collections/entry_set.rb +83 -0
  209. data/lib/spontaneous/collections/field_set.rb +53 -0
  210. data/lib/spontaneous/collections/prototype_set.rb +131 -0
  211. data/lib/spontaneous/collections/style_set.rb +13 -0
  212. data/lib/spontaneous/config.rb +156 -0
  213. data/lib/spontaneous/constants.rb +24 -0
  214. data/lib/spontaneous/content.rb +113 -0
  215. data/lib/spontaneous/content_query.rb +17 -0
  216. data/lib/spontaneous/errors.rb +48 -0
  217. data/lib/spontaneous/extensions/array.rb +18 -0
  218. data/lib/spontaneous/extensions/class.rb +17 -0
  219. data/lib/spontaneous/extensions/hash.rb +18 -0
  220. data/lib/spontaneous/extensions/json.rb +26 -0
  221. data/lib/spontaneous/extensions/kernel.rb +7 -0
  222. data/lib/spontaneous/extensions/object.rb +30 -0
  223. data/lib/spontaneous/extensions/object_space.rb +12 -0
  224. data/lib/spontaneous/extensions/string.rb +44 -0
  225. data/lib/spontaneous/facet.rb +47 -0
  226. data/lib/spontaneous/field_types/date_field.rb +12 -0
  227. data/lib/spontaneous/field_types/field.rb +252 -0
  228. data/lib/spontaneous/field_types/image_field.rb +329 -0
  229. data/lib/spontaneous/field_types/markdown_field.rb +37 -0
  230. data/lib/spontaneous/field_types/string_field.rb +14 -0
  231. data/lib/spontaneous/field_types.rb +40 -0
  232. data/lib/spontaneous/generators/page/inline.html.cut +1 -0
  233. data/lib/spontaneous/generators/page/page.html.cut.tt +4 -0
  234. data/lib/spontaneous/generators/page/page.rb.tt +9 -0
  235. data/lib/spontaneous/generators/page.rb +38 -0
  236. data/lib/spontaneous/generators/site/.gitignore +4 -0
  237. data/lib/spontaneous/generators/site/Gemfile.tt +31 -0
  238. data/lib/spontaneous/generators/site/Rakefile.tt +6 -0
  239. data/lib/spontaneous/generators/site/config/back.ru +7 -0
  240. data/lib/spontaneous/generators/site/config/boot.rb +19 -0
  241. data/lib/spontaneous/generators/site/config/database.yml.tt +21 -0
  242. data/lib/spontaneous/generators/site/config/deploy.rb.tt +0 -0
  243. data/lib/spontaneous/generators/site/config/environment.rb.tt +8 -0
  244. data/lib/spontaneous/generators/site/config/environments/development.rb.tt +15 -0
  245. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +5 -0
  246. data/lib/spontaneous/generators/site/config/front.ru +8 -0
  247. data/lib/spontaneous/generators/site/config/user_levels.yml +22 -0
  248. data/lib/spontaneous/generators/site/lib/site.rb.tt +4 -0
  249. data/lib/spontaneous/generators/site/lib/tasks/site.rake.tt +8 -0
  250. data/lib/spontaneous/generators/site/public/css/site.css +0 -0
  251. data/lib/spontaneous/generators/site/public/favicon.ico +0 -0
  252. data/lib/spontaneous/generators/site/public/js/.empty_directory +0 -0
  253. data/lib/spontaneous/generators/site/public/js/site.js +0 -0
  254. data/lib/spontaneous/generators/site/public/robots.txt +0 -0
  255. data/lib/spontaneous/generators/site/schema/.map +1 -0
  256. data/lib/spontaneous/generators/site/schema/page.rb.tt +8 -0
  257. data/lib/spontaneous/generators/site/schema/piece.rb.tt +4 -0
  258. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +13 -0
  259. data/lib/spontaneous/generators/site.rb +77 -0
  260. data/lib/spontaneous/generators.rb +23 -0
  261. data/lib/spontaneous/image_size.rb +117 -0
  262. data/lib/spontaneous/json.rb +33 -0
  263. data/lib/spontaneous/layout.rb +15 -0
  264. data/lib/spontaneous/loader.rb +280 -0
  265. data/lib/spontaneous/logger.rb +369 -0
  266. data/lib/spontaneous/media.rb +84 -0
  267. data/lib/spontaneous/page.rb +92 -0
  268. data/lib/spontaneous/page_controller.rb +18 -0
  269. data/lib/spontaneous/page_piece.rb +77 -0
  270. data/lib/spontaneous/paths.rb +30 -0
  271. data/lib/spontaneous/permissions/access_group.rb +50 -0
  272. data/lib/spontaneous/permissions/access_key.rb +35 -0
  273. data/lib/spontaneous/permissions/user.rb +167 -0
  274. data/lib/spontaneous/permissions/user_level.rb +177 -0
  275. data/lib/spontaneous/permissions.rb +55 -0
  276. data/lib/spontaneous/piece.rb +30 -0
  277. data/lib/spontaneous/plugins/aliases.rb +128 -0
  278. data/lib/spontaneous/plugins/allowed_types.rb +173 -0
  279. data/lib/spontaneous/plugins/application/facets.rb +25 -0
  280. data/lib/spontaneous/plugins/application/paths.rb +137 -0
  281. data/lib/spontaneous/plugins/application/render.rb +29 -0
  282. data/lib/spontaneous/plugins/application/serialisation.rb +16 -0
  283. data/lib/spontaneous/plugins/application/state.rb +86 -0
  284. data/lib/spontaneous/plugins/boxes.rb +84 -0
  285. data/lib/spontaneous/plugins/controllers.rb +52 -0
  286. data/lib/spontaneous/plugins/entries.rb +193 -0
  287. data/lib/spontaneous/plugins/entry.rb +51 -0
  288. data/lib/spontaneous/plugins/fields.rb +103 -0
  289. data/lib/spontaneous/plugins/instance_code.rb +18 -0
  290. data/lib/spontaneous/plugins/layouts.rb +87 -0
  291. data/lib/spontaneous/plugins/media.rb +41 -0
  292. data/lib/spontaneous/plugins/page/formats.rb +67 -0
  293. data/lib/spontaneous/plugins/page/request.rb +89 -0
  294. data/lib/spontaneous/plugins/page_search.rb +64 -0
  295. data/lib/spontaneous/plugins/page_tree.rb +25 -0
  296. data/lib/spontaneous/plugins/paths.rb +125 -0
  297. data/lib/spontaneous/plugins/permissions.rb +63 -0
  298. data/lib/spontaneous/plugins/prototypes.rb +84 -0
  299. data/lib/spontaneous/plugins/publishing.rb +255 -0
  300. data/lib/spontaneous/plugins/render.rb +24 -0
  301. data/lib/spontaneous/plugins/schema_hierarchy.rb +76 -0
  302. data/lib/spontaneous/plugins/schema_id.rb +60 -0
  303. data/lib/spontaneous/plugins/schema_title.rb +33 -0
  304. data/lib/spontaneous/plugins/serialisation.rb +67 -0
  305. data/lib/spontaneous/plugins/site/instance.rb +22 -0
  306. data/lib/spontaneous/plugins/site/map.rb +19 -0
  307. data/lib/spontaneous/plugins/site/publishing.rb +74 -0
  308. data/lib/spontaneous/plugins/site/revisions.rb +28 -0
  309. data/lib/spontaneous/plugins/site/selectors.rb +41 -0
  310. data/lib/spontaneous/plugins/site_map.rb +34 -0
  311. data/lib/spontaneous/plugins/styles.rb +119 -0
  312. data/lib/spontaneous/plugins/supertype.rb +11 -0
  313. data/lib/spontaneous/plugins/visibility.rb +151 -0
  314. data/lib/spontaneous/plugins.rb +20 -0
  315. data/lib/spontaneous/prototypes/box_prototype.rb +168 -0
  316. data/lib/spontaneous/prototypes/field_prototype.rb +112 -0
  317. data/lib/spontaneous/prototypes/layout_prototype.rb +17 -0
  318. data/lib/spontaneous/prototypes/style_prototype.rb +42 -0
  319. data/lib/spontaneous/proxy_object.rb +12 -0
  320. data/lib/spontaneous/publishing/fire_and_forget.rb +57 -0
  321. data/lib/spontaneous/publishing/immediate.rb +197 -0
  322. data/lib/spontaneous/publishing/threaded.rb +25 -0
  323. data/lib/spontaneous/publishing.rb +10 -0
  324. data/lib/spontaneous/rack/around_back.rb +44 -0
  325. data/lib/spontaneous/rack/around_front.rb +29 -0
  326. data/lib/spontaneous/rack/around_preview.rb +26 -0
  327. data/lib/spontaneous/rack/assets.rb +98 -0
  328. data/lib/spontaneous/rack/back.rb +729 -0
  329. data/lib/spontaneous/rack/front.rb +41 -0
  330. data/lib/spontaneous/rack/http.rb +18 -0
  331. data/lib/spontaneous/rack/media.rb +29 -0
  332. data/lib/spontaneous/rack/public.rb +232 -0
  333. data/lib/spontaneous/rack/reloader.rb +42 -0
  334. data/lib/spontaneous/rack/static.rb +25 -0
  335. data/lib/spontaneous/rack.rb +55 -0
  336. data/lib/spontaneous/render/context.rb +100 -0
  337. data/lib/spontaneous/render/development_renderer.rb +14 -0
  338. data/lib/spontaneous/render/engine.rb +19 -0
  339. data/lib/spontaneous/render/format/html.rb +5 -0
  340. data/lib/spontaneous/render/format.rb +70 -0
  341. data/lib/spontaneous/render/preview_renderer.rb +18 -0
  342. data/lib/spontaneous/render/published_renderer.rb +54 -0
  343. data/lib/spontaneous/render/publishing_renderer.rb +13 -0
  344. data/lib/spontaneous/render/renderer.rb +46 -0
  345. data/lib/spontaneous/render.rb +173 -0
  346. data/lib/spontaneous/revision.rb +7 -0
  347. data/lib/spontaneous/schema/schema_modification.rb +260 -0
  348. data/lib/spontaneous/schema/uid.rb +221 -0
  349. data/lib/spontaneous/schema.rb +295 -0
  350. data/lib/spontaneous/server.rb +65 -0
  351. data/lib/spontaneous/site.rb +87 -0
  352. data/lib/spontaneous/state.rb +53 -0
  353. data/lib/spontaneous/style.rb +144 -0
  354. data/lib/spontaneous/tasks/database.rake +9 -0
  355. data/lib/spontaneous/tasks.rb +5 -0
  356. data/lib/spontaneous/version.rb +6 -0
  357. data/lib/spontaneous.rb +179 -0
  358. data/spontaneous.gemspec.tmpl +66 -0
  359. data/test/disabled/test_slots.rb +287 -0
  360. data/test/experimental/test_formats.rb +92 -0
  361. data/test/experimental/test_plugins.rb +64 -0
  362. data/test/fixtures/application/css/test.less +5 -0
  363. data/test/fixtures/application/js/test.js +1 -0
  364. data/test/fixtures/application/static/favicon.ico +1 -0
  365. data/test/fixtures/application/static/test.html +1 -0
  366. data/test/fixtures/application/views/index.erubis +1 -0
  367. data/test/fixtures/back/public/test.html +1 -0
  368. data/test/fixtures/back/templates/layouts/standard.html.cut +1 -0
  369. data/test/fixtures/config/config/environment.rb +4 -0
  370. data/test/fixtures/config/config/environments/development.rb +13 -0
  371. data/test/fixtures/config/config/environments/production.rb +22 -0
  372. data/test/fixtures/config/config/environments/staging.rb +2 -0
  373. data/test/fixtures/example_application/Gemfile +6 -0
  374. data/test/fixtures/example_application/Gemfile.lock +76 -0
  375. data/test/fixtures/example_application/Rakefile +6 -0
  376. data/test/fixtures/example_application/config/back.rb +15 -0
  377. data/test/fixtures/example_application/config/back.ru +8 -0
  378. data/test/fixtures/example_application/config/back.yml +8 -0
  379. data/test/fixtures/example_application/config/boot.rb +16 -0
  380. data/test/fixtures/example_application/config/database.yml +24 -0
  381. data/test/fixtures/example_application/config/environment.rb +4 -0
  382. data/test/fixtures/example_application/config/environments/development.rb +16 -0
  383. data/test/fixtures/example_application/config/environments/production.rb +21 -0
  384. data/test/fixtures/example_application/config/environments/staging.rb +1 -0
  385. data/test/fixtures/example_application/config/front.rb +8 -0
  386. data/test/fixtures/example_application/config/front.ru +8 -0
  387. data/test/fixtures/example_application/config/front.yml +8 -0
  388. data/test/fixtures/example_application/config/schema.yml +48 -0
  389. data/test/fixtures/example_application/config/unicorn.rb +1 -0
  390. data/test/fixtures/example_application/config/user_levels.yml +19 -0
  391. data/test/fixtures/example_application/public/css/test.css +0 -0
  392. data/test/fixtures/example_application/public/favicon.ico +1 -0
  393. data/test/fixtures/example_application/public/js/test.js +0 -0
  394. data/test/fixtures/example_application/public/test.html +1 -0
  395. data/test/fixtures/example_application/schema/client_project.rb +18 -0
  396. data/test/fixtures/example_application/schema/client_projects.rb +8 -0
  397. data/test/fixtures/example_application/schema/home_page.rb +22 -0
  398. data/test/fixtures/example_application/schema/info_page.rb +13 -0
  399. data/test/fixtures/example_application/schema/inline_image.rb +11 -0
  400. data/test/fixtures/example_application/schema/page.rb +4 -0
  401. data/test/fixtures/example_application/schema/piece.rb +3 -0
  402. data/test/fixtures/example_application/schema/project.rb +21 -0
  403. data/test/fixtures/example_application/schema/project_image.rb +18 -0
  404. data/test/fixtures/example_application/schema/projects_page.rb +12 -0
  405. data/test/fixtures/example_application/schema/text.rb +8 -0
  406. data/test/fixtures/example_application/templates/client_project/images.html.cut +1 -0
  407. data/test/fixtures/example_application/templates/client_project.html.cut +4 -0
  408. data/test/fixtures/example_application/templates/client_projects.html.cut +6 -0
  409. data/test/fixtures/example_application/templates/info_page/inline.html.cut +0 -0
  410. data/test/fixtures/example_application/templates/inline_image.html.cut +1 -0
  411. data/test/fixtures/example_application/templates/layouts/home.html.cut +15 -0
  412. data/test/fixtures/example_application/templates/layouts/info.html.cut +3 -0
  413. data/test/fixtures/example_application/templates/layouts/project.html.cut +13 -0
  414. data/test/fixtures/example_application/templates/layouts/projects.html.cut +11 -0
  415. data/test/fixtures/example_application/templates/layouts/standard.html.cut +0 -0
  416. data/test/fixtures/example_application/templates/project/inline.html.cut +5 -0
  417. data/test/fixtures/example_application/templates/project.html.cut +5 -0
  418. data/test/fixtures/example_application/templates/project_image.html.cut +1 -0
  419. data/test/fixtures/example_application/templates/text.html.cut +1 -0
  420. data/test/fixtures/images/rose.greyscale.jpg +0 -0
  421. data/test/fixtures/images/rose.jpg +0 -0
  422. data/test/fixtures/images/size.gif +0 -0
  423. data/test/fixtures/images/size.jpg +0 -0
  424. data/test/fixtures/images/size.png24 +0 -0
  425. data/test/fixtures/images/size.png8 +0 -0
  426. data/test/fixtures/layouts/layouts/custom1.html.cut +1 -0
  427. data/test/fixtures/layouts/layouts/custom1.pdf.cut +0 -0
  428. data/test/fixtures/layouts/layouts/custom1.xml.cut +0 -0
  429. data/test/fixtures/layouts/layouts/custom2.html.cut +1 -0
  430. data/test/fixtures/layouts/layouts/custom3.html.cut +0 -0
  431. data/test/fixtures/layouts/layouts/standard.html.cut +1 -0
  432. data/test/fixtures/media/101/003/rose.jpg +0 -0
  433. data/test/fixtures/permissions/config/user_levels.yml +9 -0
  434. data/test/fixtures/permissions/media/image.jpg +0 -0
  435. data/test/fixtures/plugins/schema_plugin/init.rb +1 -0
  436. data/test/fixtures/plugins/schema_plugin/schema/external.rb +5 -0
  437. data/test/fixtures/plugins/schema_plugin/templates/external.html.cut +1 -0
  438. data/test/fixtures/plugins/schema_plugin/templates/from_plugin.html.cut +0 -0
  439. data/test/fixtures/plugins/schema_plugin/templates/layouts/from_plugin.html.cut +0 -0
  440. data/test/fixtures/public/templates/layouts/default.html.cut +1 -0
  441. data/test/fixtures/public/templates/layouts/default.pdf.cut +1 -0
  442. data/test/fixtures/public/templates/layouts/default.rss.cut +1 -0
  443. data/test/fixtures/public/templates/layouts/dynamic.html.cut +1 -0
  444. data/test/fixtures/public/templates/layouts/standard.html.cut +0 -0
  445. data/test/fixtures/schema/before.yml +24 -0
  446. data/test/fixtures/schema/resolvable.yml +12 -0
  447. data/test/fixtures/schema/schema.yml +7 -0
  448. data/test/fixtures/serialisation/class_hash.yaml.erb +53 -0
  449. data/test/fixtures/serialisation/root_hash.yaml.erb +184 -0
  450. data/test/fixtures/sharding/rose.jpg +0 -0
  451. data/test/fixtures/sharding/xaa +0 -0
  452. data/test/fixtures/sharding/xab +0 -0
  453. data/test/fixtures/sharding/xac +0 -0
  454. data/test/fixtures/sharding/xad +0 -0
  455. data/test/fixtures/sharding/xae +0 -0
  456. data/test/fixtures/sharding/xaf +0 -0
  457. data/test/fixtures/sharding/xag +0 -0
  458. data/test/fixtures/styles/box_a/runny.html.cut +0 -0
  459. data/test/fixtures/styles/box_a.html.cut +1 -0
  460. data/test/fixtures/styles/named2.html.cut +1 -0
  461. data/test/fixtures/styles/orange/apple.html.cut +1 -0
  462. data/test/fixtures/styles/template_class/named1.html.cut +1 -0
  463. data/test/fixtures/styles/template_class/results.html.cut +1 -0
  464. data/test/fixtures/styles/template_class/walky.html.cut +0 -0
  465. data/test/fixtures/styles/template_class.epub.cut +0 -0
  466. data/test/fixtures/styles/template_class.html.cut +1 -0
  467. data/test/fixtures/styles/template_class.pdf.cut +0 -0
  468. data/test/fixtures/styles/template_sub_class1.html.cut +1 -0
  469. data/test/fixtures/templates/aliases/a/a_style.html.cut +0 -0
  470. data/test/fixtures/templates/aliases/a/page.html.cut +0 -0
  471. data/test/fixtures/templates/aliases/a_alias/a_alias_style.html.cut +0 -0
  472. data/test/fixtures/templates/aliases/layouts/b.html.cut +1 -0
  473. data/test/fixtures/templates/aliases/layouts/b_alias.html.cut +1 -0
  474. data/test/fixtures/templates/aliases/layouts/c_alias.html.cut +1 -0
  475. data/test/fixtures/templates/boxes/blank_content/things.html.cut +1 -0
  476. data/test/fixtures/templates/boxes/my_box_class/christy.html.cut +1 -0
  477. data/test/fixtures/templates/boxes/thangs.html.cut +1 -0
  478. data/test/fixtures/templates/boxes/with_template_box.html.cut +1 -0
  479. data/test/fixtures/templates/content/include.html.cut +1 -0
  480. data/test/fixtures/templates/content/include_dir.html.cut +1 -0
  481. data/test/fixtures/templates/content/included.epub.cut +1 -0
  482. data/test/fixtures/templates/content/included.html.cut +1 -0
  483. data/test/fixtures/templates/content/partial/included.html.cut +1 -0
  484. data/test/fixtures/templates/content/preprocess.html.cut +1 -0
  485. data/test/fixtures/templates/content/second.html.cut +1 -0
  486. data/test/fixtures/templates/content/template.epub.cut +1 -0
  487. data/test/fixtures/templates/content/template.html.cut +1 -0
  488. data/test/fixtures/templates/default_style_class.html.cut +1 -0
  489. data/test/fixtures/templates/direct.html.cut +1 -0
  490. data/test/fixtures/templates/extended/grandparent.html.cut +10 -0
  491. data/test/fixtures/templates/extended/main.html.cut +6 -0
  492. data/test/fixtures/templates/extended/parent.html.cut +10 -0
  493. data/test/fixtures/templates/layouts/entries.html.cut +7 -0
  494. data/test/fixtures/templates/layouts/page_style.html.cut +1 -0
  495. data/test/fixtures/templates/layouts/params.html.cut +1 -0
  496. data/test/fixtures/templates/layouts/preview_render.html.cut +2 -0
  497. data/test/fixtures/templates/layouts/standard_page.html.cut +1 -0
  498. data/test/fixtures/templates/layouts/subdir_style.html.cut +1 -0
  499. data/test/fixtures/templates/layouts/template_params.html.cut +1 -0
  500. data/test/fixtures/templates/page_class/inline_style.html.cut +1 -0
  501. data/test/fixtures/templates/preview_render/inline.html.cut +0 -0
  502. data/test/fixtures/templates/publishing/layouts/dynamic.html.cut +1 -0
  503. data/test/fixtures/templates/publishing/layouts/static.html.cut +1 -0
  504. data/test/fixtures/templates/template_class/anonymous_style.html.cut +4 -0
  505. data/test/fixtures/templates/template_class/another_template.html.cut +0 -0
  506. data/test/fixtures/templates/template_class/complex_template.html.cut +6 -0
  507. data/test/fixtures/templates/template_class/complex_template.pdf.cut +6 -0
  508. data/test/fixtures/templates/template_class/default_template_style.html.cut +4 -0
  509. data/test/fixtures/templates/template_class/images_with_template.html.cut +5 -0
  510. data/test/fixtures/templates/template_class/slots_template.html.cut +5 -0
  511. data/test/fixtures/templates/template_class/slots_template.pdf.cut +5 -0
  512. data/test/fixtures/templates/template_class/this_template.epub.cut +1 -0
  513. data/test/fixtures/templates/template_class/this_template.html.cut +1 -0
  514. data/test/fixtures/templates/template_class/this_template.pdf.cut +1 -0
  515. data/test/fixtures/templates/with_default_style_class.html.cut +1 -0
  516. data/test/functional/test_application.rb +176 -0
  517. data/test/functional/test_back.rb +902 -0
  518. data/test/functional/test_front.rb +571 -0
  519. data/test/javascript/test_dom.rb +94 -0
  520. data/test/javascript/test_markdown.rb +97 -0
  521. data/test/slow/test_publishing.rb +987 -0
  522. data/test/slow/test_visibility.rb +250 -0
  523. data/test/support/custom_matchers.rb +77 -0
  524. data/test/support/timing.rb +23 -0
  525. data/test/test_helper.rb +164 -0
  526. data/test/test_javascript.rb +34 -0
  527. data/test/ui/test_page_editing.rb +167 -0
  528. data/test/ui_helper.rb +114 -0
  529. data/test/unit/test_alias.rb +254 -0
  530. data/test/unit/test_authentication.rb +510 -0
  531. data/test/unit/test_boxes.rb +497 -0
  532. data/test/unit/test_config.rb +156 -0
  533. data/test/unit/test_content.rb +221 -0
  534. data/test/unit/test_content_inheritance.rb +103 -0
  535. data/test/unit/test_extensions.rb +14 -0
  536. data/test/unit/test_fields.rb +392 -0
  537. data/test/unit/test_generators.rb +97 -0
  538. data/test/unit/test_image_size.rb +25 -0
  539. data/test/unit/test_images.rb +265 -0
  540. data/test/unit/test_layouts.rb +111 -0
  541. data/test/unit/test_logger.rb +80 -0
  542. data/test/unit/test_media.rb +70 -0
  543. data/test/unit/test_page.rb +244 -0
  544. data/test/unit/test_permissions.rb +834 -0
  545. data/test/unit/test_piece.rb +80 -0
  546. data/test/unit/test_prototype_set.rb +192 -0
  547. data/test/unit/test_prototypes.rb +102 -0
  548. data/test/unit/test_render.rb +359 -0
  549. data/test/unit/test_schema.rb +1009 -0
  550. data/test/unit/test_serialisation.rb +215 -0
  551. data/test/unit/test_site.rb +145 -0
  552. data/test/unit/test_structure.rb +85 -0
  553. data/test/unit/test_styles.rb +417 -0
  554. data/test/unit/test_templates.rb +224 -0
  555. data/test/unit/test_type_hierarchy.rb +28 -0
  556. metadata +1017 -0
@@ -0,0 +1,2612 @@
1
+ JS.MethodChain = function(base) {
2
+ var queue = [],
3
+ baseObject = base || {};
4
+
5
+ this.____ = function(method, args) {
6
+ queue.push({func: method, args: args});
7
+ };
8
+
9
+ this.fire = function(base) {
10
+ return JS.MethodChain.fire(queue, base || baseObject);
11
+ };
12
+ };
13
+
14
+ JS.MethodChain.fire = function(queue, object) {
15
+ var method, property, i, n;
16
+ loop: for (i = 0, n = queue.length; i < n; i++) {
17
+ method = queue[i];
18
+ if (object instanceof JS.MethodChain) {
19
+ object.____(method.func, method.args);
20
+ continue;
21
+ }
22
+ switch (typeof method.func) {
23
+ case 'string': property = object[method.func]; break;
24
+ case 'function': property = method.func; break;
25
+ case 'object': object = method.func; continue loop; break;
26
+ }
27
+ object = (typeof property === 'function')
28
+ ? property.apply(object, method.args)
29
+ : property;
30
+ }
31
+ return object;
32
+ };
33
+
34
+ JS.MethodChain.prototype = {
35
+ _: function() {
36
+ var base = arguments[0],
37
+ args, i, n;
38
+
39
+ switch (typeof base) {
40
+ case 'object': case 'function':
41
+ args = [];
42
+ for (i = 1, n = arguments.length; i < n; i++) args.push(arguments[i]);
43
+ this.____(base, args);
44
+ }
45
+ return this;
46
+ },
47
+
48
+ toFunction: function() {
49
+ var chain = this;
50
+ return function(object) { return chain.fire(object); };
51
+ }
52
+ };
53
+
54
+ JS.MethodChain.reserved = (function() {
55
+ var names = [], key;
56
+ for (key in new JS.MethodChain) names.push(key);
57
+ return new RegExp('^(?:' + names.join('|') + ')$');
58
+ })();
59
+
60
+ JS.MethodChain.addMethod = function(name) {
61
+ if (this.reserved.test(name)) return;
62
+ var func = this.prototype[name] = function() {
63
+ this.____(name, arguments);
64
+ return this;
65
+ };
66
+ func.displayName = 'MethodChain#' + name;
67
+ };
68
+
69
+ JS.MethodChain.displayName = 'MethodChain';
70
+
71
+ JS.MethodChain.addMethods = function(object) {
72
+ var methods = [], property, i;
73
+
74
+ for (property in object)
75
+ Number(property) !== property && methods.push(property);
76
+
77
+ if (object instanceof Array) {
78
+ i = object.length;
79
+ while (i--)
80
+ typeof object[i] === 'string' && methods.push(object[i]);
81
+ }
82
+ i = methods.length;
83
+ while (i--) this.addMethod(methods[i]);
84
+
85
+ object.__fns__ && this.addMethods(object.__fns__);
86
+ object.prototype && this.addMethods(object.prototype);
87
+ };
88
+
89
+ it = its = function() { return new JS.MethodChain; };
90
+
91
+ JS.Module.methodAdded(function(name) {
92
+ JS.MethodChain.addMethod(name);
93
+ });
94
+
95
+ JS.Kernel.include({
96
+ wait: function(time) {
97
+ var chain = new JS.MethodChain;
98
+
99
+ typeof time === 'number' &&
100
+ setTimeout(chain.fire.bind(chain, this), time * 1000);
101
+
102
+ this.forEach && typeof time === 'function' &&
103
+ this.forEach(function() {
104
+ setTimeout(chain.fire.bind(chain, arguments[0]), time.apply(this, arguments) * 1000);
105
+ });
106
+
107
+ return chain;
108
+ },
109
+
110
+ _: function() {
111
+ var base = arguments[0],
112
+ args = [],
113
+ i, n;
114
+
115
+ for (i = 1, n = arguments.length; i < n; i++) args.push(arguments[i]);
116
+ return (typeof base === 'object' && base) ||
117
+ (typeof base === 'function' && base.apply(this, args)) ||
118
+ this;
119
+ }
120
+ }, true);
121
+
122
+ (function() {
123
+ var queue = JS.Module.__chainq__,
124
+ n = queue.length;
125
+
126
+ while (n--) JS.MethodChain.addMethods(queue[n]);
127
+ JS.Module.__chainq__ = null;
128
+ })();
129
+
130
+ JS.MethodChain.addMethods([
131
+ "abbr", "abs", "accept", "acceptCharset", "accesskey", "acos", "action", "addEventListener",
132
+ "adjacentNode", "align", "alignWithTop", "alink", "alt", "anchor", "appendChild", "appendedNode",
133
+ "apply", "archive", "arguments", "arity", "asin", "atan", "atan2", "attrNode", "attributes",
134
+ "axis", "background", "bgcolor", "big", "blink", "blur", "bold", "border", "call", "caller",
135
+ "ceil", "cellpadding", "cellspacing", "char", "charAt", "charCodeAt", "charoff", "charset",
136
+ "checked", "childNodes", "cite", "className", "classid", "clear", "click", "clientHeight",
137
+ "clientLeft", "clientTop", "clientWidth", "cloneNode", "code", "codebase", "codetype", "color",
138
+ "cols", "colspan", "compact", "concat", "content", "coords", "cos", "data", "datetime", "declare",
139
+ "deep", "defer", "dir", "disabled", "dispatchEvent", "enctype", "event", "every", "exec", "exp",
140
+ "face", "filter", "firstChild", "fixed", "floor", "focus", "fontcolor", "fontsize", "forEach",
141
+ "frame", "frameborder", "fromCharCode", "getAttribute", "getAttributeNS", "getAttributeNode",
142
+ "getAttributeNodeNS", "getDate", "getDay", "getElementsByTagName", "getElementsByTagNameNS",
143
+ "getFullYear", "getHours", "getMilliseconds", "getMinutes", "getMonth", "getSeconds", "getTime",
144
+ "getTimezoneOffset", "getUTCDate", "getUTCDay", "getUTCFullYear", "getUTCHours",
145
+ "getUTCMilliseconds", "getUTCMinutes", "getUTCMonth", "getUTCSeconds", "getYear", "global",
146
+ "handler", "hasAttribute", "hasAttributeNS", "hasAttributes", "hasChildNodes", "hasOwnProperty",
147
+ "headers", "height", "href", "hreflang", "hspace", "htmlFor", "httpEquiv", "id", "ignoreCase",
148
+ "index", "indexOf", "innerHTML", "input", "insertBefore", "insertedNode", "isPrototypeOf", "ismap",
149
+ "italics", "join", "label", "lang", "language", "lastChild", "lastIndex", "lastIndexOf", "length",
150
+ "link", "listener", "localName", "log", "longdesc", "map", "marginheight", "marginwidth", "match",
151
+ "max", "maxlength", "media", "method", "min", "multiline", "multiple", "name", "namespace",
152
+ "namespaceURI", "nextSibling", "node", "nodeName", "nodeType", "nodeValue", "nohref", "noresize",
153
+ "normalize", "noshade", "now", "nowrap", "object", "offsetHeight", "offsetLeft", "offsetParent",
154
+ "offsetTop", "offsetWidth", "onblur", "onchange", "onclick", "ondblclick", "onfocus", "onkeydown",
155
+ "onkeypress", "onkeyup", "onload", "onmousedown", "onmousemove", "onmouseout", "onmouseover",
156
+ "onmouseup", "onreset", "onselect", "onsubmit", "onunload", "ownerDocument", "parentNode", "parse",
157
+ "pop", "pow", "prefix", "previousSibling", "profile", "prompt", "propertyIsEnumerable", "push",
158
+ "random", "readonly", "reduce", "reduceRight", "rel", "removeAttribute", "removeAttributeNS",
159
+ "removeAttributeNode", "removeChild", "removeEventListener", "removedNode", "replace",
160
+ "replaceChild", "replacedNode", "rev", "reverse", "round", "rows", "rowspan", "rules", "scheme",
161
+ "scope", "scrollHeight", "scrollIntoView", "scrollLeft", "scrollTop", "scrollWidth", "scrolling",
162
+ "search", "selected", "setAttribute", "setAttributeNS", "setAttributeNode", "setAttributeNodeNS",
163
+ "setDate", "setFullYear", "setHours", "setMilliseconds", "setMinutes", "setMonth", "setSeconds",
164
+ "setTime", "setUTCDate", "setUTCFullYear", "setUTCHours", "setUTCMilliseconds", "setUTCMinutes",
165
+ "setUTCMonth", "setUTCSeconds", "setYear", "shape", "shift", "sin", "size", "slice", "small",
166
+ "some", "sort", "source", "span", "splice", "split", "sqrt", "src", "standby", "start", "strike",
167
+ "style", "sub", "substr", "substring", "summary", "sup", "tabIndex", "tabindex", "tagName", "tan",
168
+ "target", "test", "text", "textContent", "title", "toArray", "toFunction", "toGMTString",
169
+ "toLocaleDateString", "toLocaleFormat", "toLocaleString", "toLocaleTimeString", "toLowerCase",
170
+ "toSource", "toString", "toUTCString", "toUpperCase", "type", "unshift", "unwatch", "useCapture",
171
+ "usemap", "valign", "value", "valueOf", "valuetype", "version", "vlink", "vspace", "watch", "width"
172
+ ]);
173
+
174
+
175
+ JS = (typeof JS === 'undefined') ? {} : JS;
176
+
177
+ JS.Package = function(loader) {
178
+ var Set = JS.Package.OrderedSet;
179
+ JS.Package._index(this);
180
+
181
+ this._loader = loader;
182
+ this._names = new Set();
183
+ this._deps = new Set();
184
+ this._uses = new Set();
185
+ this._observers = {};
186
+ this._events = {};
187
+ };
188
+
189
+ (function(klass) {
190
+ //================================================================
191
+ // Ordered list of unique elements, for storing dependencies
192
+
193
+ var Set = klass.OrderedSet = function(list, transform) {
194
+ this._members = this.list = [];
195
+ this._index = {};
196
+ if (!list) return;
197
+
198
+ for (var i = 0, n = list.length; i < n; i++)
199
+ this.push(transform ? transform(list[i]) : list[i]);
200
+ };
201
+
202
+ Set.prototype.push = function(item) {
203
+ var key = (item.id !== undefined) ? item.id : item,
204
+ index = this._index;
205
+
206
+ if (index.hasOwnProperty(key)) return;
207
+ index[key] = this._members.length;
208
+ this._members.push(item);
209
+ };
210
+
211
+ //================================================================
212
+ // Environment settings
213
+
214
+ klass._env = this;
215
+
216
+ if ((this.document || {}).getElementsByTagName) {
217
+ var script = document.getElementsByTagName('script')[0];
218
+ klass._isIE = (script.readyState !== undefined);
219
+ }
220
+
221
+
222
+ //================================================================
223
+ // Configuration methods, called by the DSL
224
+
225
+ var instance = klass.prototype;
226
+
227
+ instance.addDependency = function(pkg) {
228
+ this._deps.push(pkg);
229
+ };
230
+
231
+ instance.addSoftDependency = function(pkg) {
232
+ this._uses.push(pkg);
233
+ };
234
+
235
+ instance.addName = function(name) {
236
+ this._names.push(name);
237
+ klass.getFromCache(name).pkg = this;
238
+ };
239
+
240
+ instance.onload = function(block) {
241
+ this._onload = block;
242
+ };
243
+
244
+ //================================================================
245
+ // Event dispatchers, for communication between packages
246
+
247
+ instance.on = function(eventType, block, scope) {
248
+ if (this._events[eventType]) return block.call(scope);
249
+ var list = this._observers[eventType] = this._observers[eventType] || [];
250
+ list.push([block, scope]);
251
+ };
252
+
253
+ instance.fire = function(eventType) {
254
+ if (this._events[eventType]) return false;
255
+ this._events[eventType] = true;
256
+
257
+ var list = this._observers[eventType];
258
+ if (!list) return true;
259
+ delete this._observers[eventType];
260
+
261
+ for (var i = 0, n = list.length; i < n; i++)
262
+ list[i][0].call(list[i][1]);
263
+
264
+ return true;
265
+ };
266
+
267
+ //================================================================
268
+ // Loading frontend and other miscellany
269
+
270
+ instance.isLoaded = function(withExceptions) {
271
+ if (!withExceptions && this._isLoaded !== undefined) return this._isLoaded;
272
+
273
+ var names = this._names.list,
274
+ i = names.length,
275
+ name, object;
276
+
277
+ while (i--) { name = names[i];
278
+ object = klass.getObject(name);
279
+ if (object !== undefined) continue;
280
+ if (withExceptions)
281
+ throw new Error('Expected package at ' + this._loader + ' to define ' + name);
282
+ else
283
+ return this._isLoaded = false;
284
+ }
285
+ return this._isLoaded = true;
286
+ };
287
+
288
+ instance.load = function() {
289
+ if (!this.fire('request')) return;
290
+
291
+ var allDeps = this._deps.list.concat(this._uses.list),
292
+ startEvent = 'load', // could potentially use 'download' event in
293
+ listener = {}; // browsers that guarantee execution order
294
+
295
+ listener[startEvent] = this._deps.list;
296
+
297
+ klass.when(listener, function() {
298
+ klass.when({complete: allDeps, load: [this]}, function() {
299
+ this.fire('complete');
300
+ }, this);
301
+
302
+ var self = this, fireOnLoad = function() {
303
+ if (self._onload) self._onload();
304
+ self.isLoaded(true);
305
+ self.fire('load');
306
+ };
307
+
308
+ if (this.isLoaded()) {
309
+ this.fire('download');
310
+ return this.fire('load');
311
+ }
312
+
313
+ if (this._loader === undefined)
314
+ throw new Error('No load path found for ' + this._names.list[0]);
315
+
316
+ typeof this._loader === 'function'
317
+ ? this._loader(fireOnLoad)
318
+ : klass.Loader.loadFile(this._loader, fireOnLoad);
319
+
320
+ this.fire('download');
321
+ }, this);
322
+ };
323
+
324
+ instance.toString = function() {
325
+ return 'Package:' + this._names.list.join(',');
326
+ };
327
+
328
+ //================================================================
329
+ // Class-level event API, handles group listeners
330
+
331
+ klass.when = function(eventTable, block, scope) {
332
+ var eventList = [], event, packages, i;
333
+ for (event in eventTable) {
334
+ if (!eventTable.hasOwnProperty(event)) continue;
335
+ packages = new klass.OrderedSet(eventTable[event], function(name) { return klass.getByName(name) });
336
+ i = packages.list.length;
337
+ while (i--) eventList.push([event, packages.list[i]]);
338
+ }
339
+
340
+ var waiting = i = eventList.length;
341
+ if (waiting === 0) return block && block.call(scope);
342
+
343
+ while (i--) {
344
+ eventList[i][1].on(eventList[i][0], function() {
345
+ waiting -= 1;
346
+ if (waiting === 0 && block) block.call(scope);
347
+ });
348
+ eventList[i][1].load();
349
+ }
350
+ };
351
+
352
+ //================================================================
353
+ // Indexes for fast lookup by path and name, and assigning IDs
354
+
355
+ klass._autoIncrement = 1;
356
+ klass._indexByPath = {};
357
+ klass._indexByName = {};
358
+ klass._autoloaders = [];
359
+
360
+ klass._index = function(pkg) {
361
+ pkg.id = this._autoIncrement;
362
+ this._autoIncrement += 1;
363
+ };
364
+
365
+ klass.getByPath = function(loader) {
366
+ var path = loader.toString();
367
+ return this._indexByPath[path] = this._indexByPath[path] || new this(loader);
368
+ };
369
+
370
+ klass.getByName = function(name) {
371
+ if (typeof name !== 'string') return name;
372
+ var cached = this.getFromCache(name);
373
+ if (cached.pkg) return cached.pkg;
374
+
375
+ var autoloaded = this._manufacture(name);
376
+ if (autoloaded) return autoloaded;
377
+
378
+ var placeholder = new this();
379
+ placeholder.addName(name);
380
+ return placeholder;
381
+ };
382
+
383
+ //================================================================
384
+ // Auotloading API, generates packages from naming patterns
385
+
386
+ klass.autoload = function(pattern, options) {
387
+ this._autoloaders.push([pattern, options]);
388
+ };
389
+
390
+ klass._manufacture = function(name) {
391
+ var autoloaders = this._autoloaders,
392
+ n = autoloaders.length,
393
+ i, autoloader, path;
394
+
395
+ for (i = 0; i < n; i++) {
396
+ autoloader = autoloaders[i];
397
+ if (!autoloader[0].test(name)) continue;
398
+
399
+ path = autoloader[1].from + '/' +
400
+ name.replace(/([a-z])([A-Z])/g, function(m,a,b) { return a + '_' + b })
401
+ .replace(/\./g, '/')
402
+ .toLowerCase() + '.js';
403
+
404
+ pkg = new this(path);
405
+ pkg.addName(name);
406
+
407
+ if (path = autoloader[1].require)
408
+ pkg.addDependency(name.replace(autoloader[0], path));
409
+
410
+ return pkg;
411
+ }
412
+ return null;
413
+ };
414
+
415
+ //================================================================
416
+ // Cache for named packages and runtime objects
417
+
418
+ klass.getFromCache = function(name) {
419
+ return this._indexByName[name] = this._indexByName[name] || {};
420
+ };
421
+
422
+ klass.getObject = function(name) {
423
+ var cached = this.getFromCache(name);
424
+ if (cached.obj !== undefined) return cached.obj;
425
+
426
+ var object = this._env,
427
+ parts = name.split('.'), part;
428
+
429
+ while (part = parts.shift()) object = object && object[part];
430
+
431
+ return this.getFromCache(name).obj = object;
432
+ };
433
+
434
+ })(JS.Package);
435
+
436
+
437
+ JS.Package.DomLoader = {
438
+ usable: function() {
439
+ return !!JS.Package.getObject('window.document.getElementsByTagName');
440
+ },
441
+
442
+ __FILE__: function() {
443
+ var scripts = document.getElementsByTagName('script');
444
+ return scripts[scripts.length - 1].src;
445
+ },
446
+
447
+ loadFile: function(path, fireCallbacks) {
448
+ var self = this,
449
+ tag = document.createElement('script');
450
+
451
+ tag.type = 'text/javascript';
452
+ tag.src = path;
453
+
454
+ tag.onload = tag.onreadystatechange = function() {
455
+ var state = tag.readyState, status = tag.status;
456
+ if ( !state || state === 'loaded' || state === 'complete' || (state === 4 && status === 200) ) {
457
+ fireCallbacks();
458
+ tag.onload = tag.onreadystatechange = self._K;
459
+ tag = null;
460
+ }
461
+ };
462
+
463
+ if (window.console && console.info)
464
+ console.info('Loading ' + path);
465
+
466
+ document.getElementsByTagName('head')[0].appendChild(tag);
467
+ },
468
+
469
+ _K: function() {}
470
+ };
471
+
472
+ JS.Package.CommonJSLoader = {
473
+ usable: function() {
474
+ return typeof require === 'function' &&
475
+ typeof exports === 'object';
476
+ },
477
+
478
+ setup: function() {
479
+ var self = this;
480
+ require = (function(oridRequire) {
481
+ return function() {
482
+ self._currentPath = arguments[0] + '.js';
483
+ return oridRequire.apply(JS.Package._env, arguments);
484
+ };
485
+ })(require);
486
+ },
487
+
488
+ __FILE__: function() {
489
+ return this._currentPath;
490
+ },
491
+
492
+ loadFile: function(path, fireCallbacks) {
493
+ var node = (typeof process === 'object'),
494
+ cwd = node ? process.cwd() : require('file').cwd(),
495
+ module = path.replace(/\.[^\.]+$/g, ''),
496
+ file = node ? require('path') : require('file');
497
+
498
+ require(file.join(cwd, module));
499
+ fireCallbacks();
500
+ }
501
+ };
502
+
503
+ JS.Package.ServerLoader = {
504
+ usable: function() {
505
+ return typeof JS.Package.getObject('load') === 'function' &&
506
+ typeof JS.Package.getObject('version') === 'function';
507
+ },
508
+
509
+ setup: function() {
510
+ var self = this;
511
+ load = (function(origLoad) {
512
+ return function() {
513
+ self._currentPath = arguments[0];
514
+ return origLoad.apply(JS.Package._env, arguments);
515
+ };
516
+ })(load);
517
+ },
518
+
519
+ __FILE__: function() {
520
+ return this._currentPath;
521
+ },
522
+
523
+ loadFile: function(path, fireCallbacks) {
524
+ load(path);
525
+ fireCallbacks();
526
+ }
527
+ };
528
+
529
+ JS.Package.WshLoader = {
530
+ usable: function() {
531
+ return !!JS.Package.getObject('ActiveXObject') &&
532
+ !!JS.Package.getObject('WScript');
533
+ },
534
+
535
+ __FILE__: function() {
536
+ return this._currentPath;
537
+ },
538
+
539
+ loadFile: function(path, fireCallbacks) {
540
+ this._currentPath = path;
541
+ var fso = new ActiveXObject('Scripting.FileSystemObject'), file, runner;
542
+ try {
543
+ file = fso.OpenTextFile(path);
544
+ runner = function() { eval(file.ReadAll()) };
545
+ runner();
546
+ fireCallbacks();
547
+ } finally {
548
+ try { if (file) file.Close() } catch (e) {}
549
+ }
550
+ }
551
+ };
552
+
553
+ (function() {
554
+ var candidates = [ JS.Package.DomLoader,
555
+ JS.Package.CommonJSLoader,
556
+ JS.Package.ServerLoader,
557
+ JS.Package.WshLoader ],
558
+
559
+ n = candidates.length,
560
+ i, candidate;
561
+
562
+ for (i = 0; i < n; i++) {
563
+ candidate = candidates[i];
564
+ if (candidate.usable()) {
565
+ JS.Package.Loader = candidate;
566
+ if (candidate.setup) candidate.setup();
567
+ break;
568
+ }
569
+ }
570
+ })();
571
+
572
+
573
+ JS.Package.DSL = {
574
+ __FILE__: function() {
575
+ return JS.Package.Loader.__FILE__();
576
+ },
577
+
578
+ pkg: function(name, path) {
579
+ var pkg = path
580
+ ? JS.Package.getByPath(path)
581
+ : JS.Package.getByName(name);
582
+ pkg.addName(name);
583
+ return new JS.Package.Description(pkg);
584
+ },
585
+
586
+ file: function(path) {
587
+ var pkg = JS.Package.getByPath(path);
588
+ return new JS.Package.Description(pkg);
589
+ },
590
+
591
+ load: function(path, fireCallbacks) {
592
+ JS.Package.Loader.loadFile(path, fireCallbacks);
593
+ },
594
+
595
+ autoload: function(pattern, options) {
596
+ JS.Package.autoload(pattern, options);
597
+ }
598
+ };
599
+
600
+ JS.Package.Description = function(pkg) {
601
+ this._pkg = pkg;
602
+ };
603
+
604
+ (function(klass) {
605
+
606
+ klass._batch = function(method, args) {
607
+ var n = args.length, method = this._pkg[method], i;
608
+ for (i = 0; i < n; i++) method.call(this._pkg, args[i]);
609
+ return this;
610
+ };
611
+
612
+ klass.provides = function() {
613
+ return this._batch('addName', arguments);
614
+ };
615
+
616
+ klass.requires = function() {
617
+ return this._batch('addDependency', arguments);
618
+ };
619
+
620
+ klass.uses = function() {
621
+ return this._batch('addSoftDependency', arguments);
622
+ };
623
+
624
+ klass.setup = function(block) {
625
+ this._pkg.onload(block);
626
+ return this;
627
+ };
628
+
629
+ })(JS.Package.Description.prototype);
630
+
631
+ JS.Package.DSL.loader = JS.Package.DSL.file;
632
+
633
+ JS.Packages = function(declaration) {
634
+ declaration.call(JS.Package.DSL);
635
+ };
636
+
637
+ JS.require = function() {
638
+ var requirements = [], i = 0;
639
+
640
+ while (typeof arguments[i] === 'string'){
641
+ requirements.push(arguments[i]);
642
+ i += 1;
643
+ }
644
+
645
+ JS.Package.when({complete: requirements}, arguments[i], arguments[i+1]);
646
+ };
647
+
648
+
649
+ JS.Comparable = new JS.Module('Comparable', {
650
+ extend: {
651
+ ClassMethods: new JS.Module({
652
+ compare: function(one, another) {
653
+ return one.compareTo(another);
654
+ }
655
+ }),
656
+
657
+ included: function(base) {
658
+ base.extend(this.ClassMethods);
659
+ }
660
+ },
661
+
662
+ lt: function(other) {
663
+ return this.compareTo(other) < 0;
664
+ },
665
+
666
+ lte: function(other) {
667
+ return this.compareTo(other) < 1;
668
+ },
669
+
670
+ gt: function(other) {
671
+ return this.compareTo(other) > 0;
672
+ },
673
+
674
+ gte: function(other) {
675
+ return this.compareTo(other) > -1;
676
+ },
677
+
678
+ eq: function(other) {
679
+ return this.compareTo(other) === 0;
680
+ },
681
+
682
+ between: function(a, b) {
683
+ return this.gte(a) && this.lte(b);
684
+ }
685
+ });
686
+
687
+
688
+ JS.Enumerable = new JS.Module('Enumerable', {
689
+ extend: {
690
+ forEach: function(block, context) {
691
+ if (!block) return new JS.Enumerator(this, 'forEach');
692
+ for (var i = 0, n = this.length; i < n; i++) {
693
+ if (this[i] !== undefined)
694
+ block.call(context || null, this[i]);
695
+ }
696
+ return this;
697
+ },
698
+
699
+ isComparable: function(list) {
700
+ return list.all(function(item) { return JS.isFn(item.compareTo) });
701
+ },
702
+
703
+ areEqual: function(one, another) {
704
+ return one.equals
705
+ ? one.equals(another)
706
+ : (one === another);
707
+ },
708
+
709
+ Collection: new JS.Class({
710
+ initialize: function(array) {
711
+ this.length = 0;
712
+ var push = Array.prototype.push;
713
+ JS.Enumerable.forEach.call(array, function(item) {
714
+ push.call(this, item);
715
+ }, this);
716
+ }
717
+ })
718
+ },
719
+
720
+ all: function(block, context) {
721
+ block = JS.Enumerable.toFn(block);
722
+ var truth = true;
723
+ this.forEach(function(item) {
724
+ truth = truth && (block ? block.apply(context || null, arguments) : item);
725
+ });
726
+ return !!truth;
727
+ },
728
+
729
+ any: function(block, context) {
730
+ block = JS.Enumerable.toFn(block);
731
+ var truth = false;
732
+ this.forEach(function(item) {
733
+ truth = truth || (block ? block.apply(context || null, arguments) : item);
734
+ });
735
+ return !!truth;
736
+ },
737
+
738
+ count: function(block, context) {
739
+ if (JS.isFn(this.size)) return this.size();
740
+ var count = 0, object = block;
741
+
742
+ if (block && !JS.isFn(block))
743
+ block = function(x) { return JS.Enumerable.areEqual(x, object) };
744
+
745
+ this.forEach(function() {
746
+ if (!block || block.apply(context || null, arguments))
747
+ count += 1;
748
+ });
749
+ return count;
750
+ },
751
+
752
+ cycle: function(n, block, context) {
753
+ if (!block) return this.enumFor('cycle', n);
754
+ block = JS.Enumerable.toFn(block);
755
+ while (n--) this.forEach(block, context);
756
+ },
757
+
758
+ drop: function(n) {
759
+ var entries = [];
760
+ this.forEachWithIndex(function(item, i) {
761
+ if (i >= n) entries.push(item);
762
+ });
763
+ return entries;
764
+ },
765
+
766
+ dropWhile: function(block, context) {
767
+ if (!block) return this.enumFor('dropWhile');
768
+ block = JS.Enumerable.toFn(block);
769
+
770
+ var entries = [],
771
+ drop = true;
772
+
773
+ this.forEach(function(item) {
774
+ if (drop) drop = drop && block.apply(context || null, arguments);
775
+ if (!drop) entries.push(item);
776
+ });
777
+ return entries;
778
+ },
779
+
780
+ forEachCons: function(n, block, context) {
781
+ if (!block) return this.enumFor('forEachCons', n);
782
+ block = JS.Enumerable.toFn(block);
783
+
784
+ var entries = this.toArray(),
785
+ size = entries.length,
786
+ limit = size - n,
787
+ i;
788
+
789
+ for (i = 0; i <= limit; i++)
790
+ block.call(context || null, entries.slice(i, i+n));
791
+
792
+ return this;
793
+ },
794
+
795
+ forEachSlice: function(n, block, context) {
796
+ if (!block) return this.enumFor('forEachSlice', n);
797
+ block = JS.Enumerable.toFn(block);
798
+
799
+ var entries = this.toArray(),
800
+ size = entries.length,
801
+ m = Math.ceil(size/n),
802
+ i;
803
+
804
+ for (i = 0; i < m; i++)
805
+ block.call(context || null, entries.slice(i*n, (i+1)*n));
806
+
807
+ return this;
808
+ },
809
+
810
+ forEachWithIndex: function(offset, block, context) {
811
+ if (JS.isFn(offset)) {
812
+ context = block;
813
+ block = offset;
814
+ offset = 0;
815
+ }
816
+ offset = offset || 0;
817
+
818
+ if (!block) return this.enumFor('forEachWithIndex', offset);
819
+ block = JS.Enumerable.toFn(block);
820
+
821
+ return this.forEach(function(item) {
822
+ var result = block.call(context || null, item, offset);
823
+ offset += 1;
824
+ return result;
825
+ });
826
+ },
827
+
828
+ forEachWithObject: function(object, block, context) {
829
+ if (!block) return this.enumFor('forEachWithObject', object);
830
+ block = JS.Enumerable.toFn(block);
831
+
832
+ this.forEach(function() {
833
+ var args = [object].concat(JS.array(arguments));
834
+ block.apply(context || null, args);
835
+ });
836
+ return object;
837
+ },
838
+
839
+ find: function(block, context) {
840
+ if (!block) return this.enumFor('find');
841
+ block = JS.Enumerable.toFn(block);
842
+
843
+ var needle = {}, K = needle;
844
+ this.forEach(function(item) {
845
+ if (needle !== K) return;
846
+ needle = block.apply(context || null, arguments) ? item : needle;
847
+ });
848
+ return needle === K ? null : needle;
849
+ },
850
+
851
+ findIndex: function(needle, context) {
852
+ if (needle === undefined) return this.enumFor('findIndex');
853
+
854
+ var index = null,
855
+ block = JS.isFn(needle);
856
+
857
+ this.forEachWithIndex(function(item, i) {
858
+ if (index !== null) return;
859
+ if (JS.Enumerable.areEqual(needle, item) || (block && needle.apply(context || null, arguments)))
860
+ index = i;
861
+ });
862
+ return index;
863
+ },
864
+
865
+ first: function(n) {
866
+ var entries = this.toArray();
867
+ return (n === undefined) ? entries[0] : entries.slice(0,n);
868
+ },
869
+
870
+ grep: function(pattern, block, context) {
871
+ block = JS.Enumerable.toFn(block);
872
+ var results = [];
873
+ this.forEach(function(item) {
874
+ var match = JS.isFn(pattern.match) ? pattern.match(item) : pattern(item);
875
+ if (!match) return;
876
+ if (block) item = block.apply(context || null, arguments);
877
+ results.push(item);
878
+ });
879
+ return results;
880
+ },
881
+
882
+ groupBy: function(block, context) {
883
+ if (!block) return this.enumFor('groupBy');
884
+ block = JS.Enumerable.toFn(block);
885
+
886
+ var hash = new JS.Hash();
887
+ this.forEach(function(item) {
888
+ var value = block.apply(context || null, arguments);
889
+ if (!hash.hasKey(value)) hash.store(value, []);
890
+ hash.get(value).push(item);
891
+ });
892
+ return hash;
893
+ },
894
+
895
+ inject: function(memo, block, context) {
896
+ var args = JS.array(arguments),
897
+ counter = 0,
898
+ K = {};
899
+
900
+ switch (args.length) {
901
+ case 1: memo = K;
902
+ block = args[0];
903
+ break;
904
+
905
+ case 2: if (JS.isFn(memo)) {
906
+ memo = K;
907
+ block = args[0];
908
+ context = args[1];
909
+ }
910
+ }
911
+ block = JS.Enumerable.toFn(block);
912
+
913
+ this.forEach(function(item) {
914
+ if (!counter++ && memo === K) return memo = item;
915
+ var args = [memo].concat(JS.array(arguments));
916
+ memo = block.apply(context || null, args);
917
+ });
918
+ return memo;
919
+ },
920
+
921
+ map: function(block, context) {
922
+ if (!block) return this.enumFor('map');
923
+ block = JS.Enumerable.toFn(block);
924
+
925
+ var map = [];
926
+ this.forEach(function() {
927
+ map.push(block.apply(context || null, arguments));
928
+ });
929
+ return map;
930
+ },
931
+
932
+ max: function(block, context) {
933
+ return this.minmax(block, context)[1];
934
+ },
935
+
936
+ maxBy: function(block, context) {
937
+ if (!block) return this.enumFor('maxBy');
938
+ return this.minmaxBy(block, context)[1];
939
+ },
940
+
941
+ member: function(needle) {
942
+ return this.any(function(item) { return JS.Enumerable.areEqual(item, needle) });
943
+ },
944
+
945
+ min: function(block, context) {
946
+ return this.minmax(block, context)[0];
947
+ },
948
+
949
+ minBy: function(block, context) {
950
+ if (!block) return this.enumFor('minBy');
951
+ return this.minmaxBy(block, context)[0];
952
+ },
953
+
954
+ minmax: function(block, context) {
955
+ var list = this.sort(block, context);
956
+ return [list[0], list[list.length - 1]];
957
+ },
958
+
959
+ minmaxBy: function(block, context) {
960
+ if (!block) return this.enumFor('minmaxBy');
961
+ var list = this.sortBy(block, context);
962
+ return [list[0], list[list.length - 1]];
963
+ },
964
+
965
+ none: function(block, context) {
966
+ return !this.any(block, context);
967
+ },
968
+
969
+ one: function(block, context) {
970
+ block = JS.Enumerable.toFn(block);
971
+ var count = 0;
972
+ this.forEach(function(item) {
973
+ if (block ? block.apply(context || null, arguments) : item) count += 1;
974
+ });
975
+ return count === 1;
976
+ },
977
+
978
+ partition: function(block, context) {
979
+ if (!block) return this.enumFor('partition');
980
+ block = JS.Enumerable.toFn(block);
981
+
982
+ var ayes = [], noes = [];
983
+ this.forEach(function(item) {
984
+ (block.apply(context || null, arguments) ? ayes : noes).push(item);
985
+ });
986
+ return [ayes, noes];
987
+ },
988
+
989
+ reject: function(block, context) {
990
+ if (!block) return this.enumFor('reject');
991
+ block = JS.Enumerable.toFn(block);
992
+
993
+ var map = [];
994
+ this.forEach(function(item) {
995
+ if (!block.apply(context || null, arguments)) map.push(item);
996
+ });
997
+ return map;
998
+ },
999
+
1000
+ reverseForEach: function(block, context) {
1001
+ if (!block) return this.enumFor('reverseForEach');
1002
+ block = JS.Enumerable.toFn(block);
1003
+
1004
+ var entries = this.toArray(),
1005
+ n = entries.length;
1006
+
1007
+ while (n--) block.call(context || null, entries[n]);
1008
+ return this;
1009
+ },
1010
+
1011
+ select: function(block, context) {
1012
+ if (!block) return this.enumFor('select');
1013
+ block = JS.Enumerable.toFn(block);
1014
+
1015
+ var map = [];
1016
+ this.forEach(function(item) {
1017
+ if (block.apply(context || null, arguments)) map.push(item);
1018
+ });
1019
+ return map;
1020
+ },
1021
+
1022
+ sort: function(block, context) {
1023
+ var comparable = JS.Enumerable.isComparable(this),
1024
+ entries = this.toArray();
1025
+
1026
+ block = block || (comparable
1027
+ ? function(a,b) { return a.compareTo(b); }
1028
+ : null);
1029
+ return block
1030
+ ? entries.sort(function(a,b) { return block.call(context || null, a, b); })
1031
+ : entries.sort();
1032
+ },
1033
+
1034
+ sortBy: function(block, context) {
1035
+ if (!block) return this.enumFor('sortBy');
1036
+ block = JS.Enumerable.toFn(block);
1037
+
1038
+ var util = JS.Enumerable,
1039
+ map = new util.Collection(this.map(block, context)),
1040
+ comparable = util.isComparable(map);
1041
+
1042
+ return new util.Collection(map.zip(this).sort(function(a, b) {
1043
+ a = a[0]; b = b[0];
1044
+ return comparable ? a.compareTo(b) : (a < b ? -1 : (a > b ? 1 : 0));
1045
+ })).map(function(item) { return item[1]; });
1046
+ },
1047
+
1048
+ take: function(n) {
1049
+ var entries = [];
1050
+ this.forEachWithIndex(function(item, i) {
1051
+ if (i < n) entries.push(item);
1052
+ });
1053
+ return entries;
1054
+ },
1055
+
1056
+ takeWhile: function(block, context) {
1057
+ if (!block) return this.enumFor('takeWhile');
1058
+ block = JS.Enumerable.toFn(block);
1059
+
1060
+ var entries = [],
1061
+ take = true;
1062
+ this.forEach(function(item) {
1063
+ if (take) take = take && block.apply(context || null, arguments);
1064
+ if (take) entries.push(item);
1065
+ });
1066
+ return entries;
1067
+ },
1068
+
1069
+ toArray: function() {
1070
+ return this.drop(0);
1071
+ },
1072
+
1073
+ zip: function() {
1074
+ var util = JS.Enumerable,
1075
+ args = [],
1076
+ counter = 0,
1077
+ n = arguments.length,
1078
+ block, context;
1079
+
1080
+ if (JS.isFn(arguments[n-1])) {
1081
+ block = arguments[n-1]; context = {};
1082
+ }
1083
+ if (JS.isFn(arguments[n-2])) {
1084
+ block = arguments[n-2]; context = arguments[n-1];
1085
+ }
1086
+ util.forEach.call(arguments, function(arg) {
1087
+ if (arg === block || arg === context) return;
1088
+ if (arg.toArray) arg = arg.toArray();
1089
+ if (JS.isType(arg, Array)) args.push(arg);
1090
+ });
1091
+ var results = this.map(function(item) {
1092
+ var zip = [item];
1093
+ util.forEach.call(args, function(arg) {
1094
+ zip.push(arg[counter] === undefined ? null : arg[counter]);
1095
+ });
1096
+ return ++counter && zip;
1097
+ });
1098
+ if (!block) return results;
1099
+ util.forEach.call(results, block, context);
1100
+ }
1101
+ });
1102
+
1103
+ // http://developer.mozilla.org/en/docs/index.php?title=Core_JavaScript_1.5_Reference:Global_Objects:Array&oldid=58326
1104
+ JS.Enumerable.include({
1105
+ forEach: JS.Enumerable.forEach,
1106
+ collect: JS.Enumerable.instanceMethod('map'),
1107
+ detect: JS.Enumerable.instanceMethod('find'),
1108
+ entries: JS.Enumerable.instanceMethod('toArray'),
1109
+ every: JS.Enumerable.instanceMethod('all'),
1110
+ findAll: JS.Enumerable.instanceMethod('select'),
1111
+ filter: JS.Enumerable.instanceMethod('select'),
1112
+ some: JS.Enumerable.instanceMethod('any'),
1113
+
1114
+ extend: {
1115
+ toFn: function(object) {
1116
+ if (!object) return object;
1117
+ if (object.toFunction) return object.toFunction();
1118
+ if (this.OPS[object]) return this.OPS[object];
1119
+ if (JS.isType(object, 'string') || JS.isType(object, String))
1120
+ return function() {
1121
+ var args = JS.array(arguments),
1122
+ target = args.shift(),
1123
+ method = target[object];
1124
+ return JS.isFn(method) ? method.apply(target, args) : method;
1125
+ };
1126
+ return object;
1127
+ },
1128
+
1129
+ OPS: {
1130
+ '+': function(a,b) { return a + b },
1131
+ '-': function(a,b) { return a - b },
1132
+ '*': function(a,b) { return a * b },
1133
+ '/': function(a,b) { return a / b },
1134
+ '%': function(a,b) { return a % b },
1135
+ '^': function(a,b) { return a ^ b },
1136
+ '&': function(a,b) { return a & b },
1137
+ '&&': function(a,b) { return a && b },
1138
+ '|': function(a,b) { return a | b },
1139
+ '||': function(a,b) { return a || b },
1140
+ '==': function(a,b) { return a == b },
1141
+ '!=': function(a,b) { return a != b },
1142
+ '>': function(a,b) { return a > b },
1143
+ '>=': function(a,b) { return a >= b },
1144
+ '<': function(a,b) { return a < b },
1145
+ '<=': function(a,b) { return a <= b },
1146
+ '===': function(a,b) { return a === b },
1147
+ '!==': function(a,b) { return a !== b },
1148
+ '[]': function(a,b) { return a[b] },
1149
+ '()': function(a,b) { return a(b) }
1150
+ },
1151
+
1152
+ Enumerator: new JS.Class({
1153
+ include: JS.Enumerable,
1154
+
1155
+ extend: {
1156
+ DEFAULT_METHOD: 'forEach'
1157
+ },
1158
+
1159
+ initialize: function(object, method, args) {
1160
+ this._object = object;
1161
+ this._method = method || this.klass.DEFAULT_METHOD;
1162
+ this._args = (args || []).slice();
1163
+ },
1164
+
1165
+ forEach: function(block, context) {
1166
+ if (!block) return this;
1167
+ var args = this._args.slice();
1168
+ args.push(block);
1169
+ if (context) args.push(context);
1170
+ return this._object[this._method].apply(this._object, args);
1171
+ },
1172
+
1173
+ cons: JS.Enumerable.instanceMethod('forEachCons'),
1174
+ reverse: JS.Enumerable.instanceMethod('reverseForEach'),
1175
+ slice: JS.Enumerable.instanceMethod('forEachSlice'),
1176
+ withIndex: JS.Enumerable.instanceMethod('forEachWithIndex'),
1177
+ withObject: JS.Enumerable.instanceMethod('forEachWithObject')
1178
+ })
1179
+ }
1180
+ }, false);
1181
+
1182
+ JS.Enumerable.Collection.include(JS.Enumerable, true);
1183
+
1184
+ JS.Kernel.include({
1185
+ enumFor: function(method) {
1186
+ var args = JS.array(arguments),
1187
+ method = args.shift();
1188
+ return new JS.Enumerable.Enumerator(this, method, args);
1189
+ }
1190
+ }, false);
1191
+
1192
+ JS.Kernel.define('toEnum', JS.Kernel.instanceMethod('enumFor'), true);
1193
+
1194
+
1195
+ JS.LinkedList = new JS.Class('LinkedList', {
1196
+ include: JS.Enumerable || {},
1197
+
1198
+ initialize: function(array, useNodes) {
1199
+ this.length = 0;
1200
+ this.first = this.last = null;
1201
+ if (!array) return;
1202
+ for (var i = 0, n = array.length; i < n; i++)
1203
+ this.push( useNodes ? new this.klass.Node(array[i]) : array[i] );
1204
+ },
1205
+
1206
+ forEach: function(block, context) {
1207
+ if (!block) return this.enumFor('forEach');
1208
+ block = JS.Enumerable.toFn(block);
1209
+
1210
+ var node = this.first,
1211
+ next, i, n;
1212
+
1213
+ for (i = 0, n = this.length; i < n; i++) {
1214
+ next = node.next;
1215
+ block.call(context || null, node, i);
1216
+ if (node === this.last) break;
1217
+ node = next;
1218
+ }
1219
+ return this;
1220
+ },
1221
+
1222
+ at: function(n) {
1223
+ if (n < 0 || n >= this.length) return undefined;
1224
+ var node = this.first;
1225
+ while (n--) node = node.next;
1226
+ return node;
1227
+ },
1228
+
1229
+ pop: function() {
1230
+ return this.length ? this.remove(this.last) : undefined;
1231
+ },
1232
+
1233
+ shift: function() {
1234
+ return this.length ? this.remove(this.first) : undefined;
1235
+ },
1236
+
1237
+ // stubs - should be implemented by concrete list types
1238
+ insertAfter: function() {},
1239
+ push: function() {},
1240
+ remove: function() {},
1241
+
1242
+ extend: {
1243
+ Node: new JS.Class({
1244
+ initialize: function(data) {
1245
+ this.data = data;
1246
+ this.prev = this.next = this.list = null;
1247
+ }
1248
+ })
1249
+ }
1250
+ });
1251
+
1252
+ JS.LinkedList.Doubly = new JS.Class('LinkedList.Doubly', JS.LinkedList, {
1253
+ insertAt: function(n, newNode) {
1254
+ if (n < 0 || n >= this.length) return;
1255
+ this.insertBefore(this.at(n), newNode);
1256
+ },
1257
+
1258
+ unshift: function(newNode) {
1259
+ this.length > 0
1260
+ ? this.insertBefore(this.first, newNode)
1261
+ : this.push(newNode);
1262
+ },
1263
+
1264
+ insertBefore: function() {}
1265
+ });
1266
+
1267
+ JS.LinkedList.insertTemplate = function(prev, next, pos) {
1268
+ return function(node, newNode) {
1269
+ if (node.list !== this) return;
1270
+ newNode[prev] = node;
1271
+ newNode[next] = node[next];
1272
+ node[next] = (node[next][prev] = newNode);
1273
+ if (newNode[prev] === this[pos]) this[pos] = newNode;
1274
+ newNode.list = this;
1275
+ this.length++;
1276
+ };
1277
+ };
1278
+
1279
+ JS.LinkedList.Doubly.Circular = new JS.Class('LinkedList.Doubly.Circular', JS.LinkedList.Doubly, {
1280
+ insertAfter: JS.LinkedList.insertTemplate('prev', 'next', 'last'),
1281
+ insertBefore: JS.LinkedList.insertTemplate('next', 'prev', 'first'),
1282
+
1283
+ push: function(newNode) {
1284
+ if (this.length)
1285
+ return this.insertAfter(this.last, newNode);
1286
+
1287
+ this.first = this.last =
1288
+ newNode.prev = newNode.next = newNode;
1289
+
1290
+ newNode.list = this;
1291
+ this.length = 1;
1292
+ },
1293
+
1294
+ remove: function(removed) {
1295
+ if (removed.list !== this || this.length === 0) return null;
1296
+ if (this.length > 1) {
1297
+ removed.prev.next = removed.next;
1298
+ removed.next.prev = removed.prev;
1299
+ if (removed === this.first) this.first = removed.next;
1300
+ if (removed === this.last) this.last = removed.prev;
1301
+ } else {
1302
+ this.first = this.last = null;
1303
+ }
1304
+ removed.prev = removed.next = removed.list = null;
1305
+ this.length--;
1306
+ return removed;
1307
+ }
1308
+ });
1309
+
1310
+
1311
+ JS.Hash = new JS.Class('Hash', {
1312
+ include: JS.Enumerable || {},
1313
+
1314
+ extend: {
1315
+ Pair: new JS.Class({
1316
+ include: JS.Comparable || {},
1317
+
1318
+ setKey: function(key) {
1319
+ this[0] = this.key = key;
1320
+ },
1321
+
1322
+ hasKey: function(key) {
1323
+ var my = this.key;
1324
+ return my.equals ? my.equals(key) : my === key;
1325
+ },
1326
+
1327
+ setValue: function(value) {
1328
+ this[1] = this.value = value;
1329
+ },
1330
+
1331
+ hasValue: function(value) {
1332
+ var my = this.value;
1333
+ return my.equals ? my.equals(value) : my === value;
1334
+ },
1335
+
1336
+ compareTo: function(other) {
1337
+ return this.key.compareTo
1338
+ ? this.key.compareTo(other.key)
1339
+ : (this.key < other.key ? -1 : (this.key > other.key ? 1 : 0));
1340
+ },
1341
+
1342
+ hash: function() {
1343
+ var key = JS.Hash.codeFor(this.key),
1344
+ value = JS.Hash.codeFor(this.value);
1345
+
1346
+ return [key, value].sort().join('');
1347
+ }
1348
+ }),
1349
+
1350
+ codeFor: function(object) {
1351
+ if (typeof object !== 'object') return String(object);
1352
+ return JS.isFn(object.hash)
1353
+ ? object.hash()
1354
+ : object.toString();
1355
+ }
1356
+ },
1357
+
1358
+ initialize: function(object) {
1359
+ this.clear();
1360
+ if (!JS.isType(object, Array)) return this.setDefault(object);
1361
+ for (var i = 0, n = object.length; i < n; i += 2)
1362
+ this.store(object[i], object[i+1]);
1363
+ },
1364
+
1365
+ forEach: function(block, context) {
1366
+ if (!block) return this.enumFor('forEach');
1367
+ block = JS.Enumerable.toFn(block);
1368
+
1369
+ var hash, bucket, i;
1370
+
1371
+ for (hash in this._buckets) {
1372
+ if (!this._buckets.hasOwnProperty(hash)) continue;
1373
+ bucket = this._buckets[hash];
1374
+ i = bucket.length;
1375
+ while (i--) block.call(context || null, bucket[i]);
1376
+ }
1377
+ return this;
1378
+ },
1379
+
1380
+ _bucketForKey: function(key, createIfAbsent) {
1381
+ var hash = this.klass.codeFor(key),
1382
+ bucket = this._buckets[hash];
1383
+
1384
+ if (!bucket && createIfAbsent)
1385
+ bucket = this._buckets[hash] = [];
1386
+
1387
+ return bucket;
1388
+ },
1389
+
1390
+ _indexInBucket: function(bucket, key) {
1391
+ var i = bucket.length,
1392
+ ident = !!this._compareByIdentity;
1393
+
1394
+ while (i--) {
1395
+ if (ident ? (bucket[i].key === key) : bucket[i].hasKey(key))
1396
+ return i;
1397
+ }
1398
+ return -1;
1399
+ },
1400
+
1401
+ assoc: function(key, createIfAbsent) {
1402
+ var bucket, index, pair;
1403
+
1404
+ bucket = this._bucketForKey(key, createIfAbsent);
1405
+ if (!bucket) return null;
1406
+
1407
+ index = this._indexInBucket(bucket, key);
1408
+ if (index > -1) return bucket[index];
1409
+ if (!createIfAbsent) return null;
1410
+
1411
+ this.size += 1; this.length += 1;
1412
+ pair = new this.klass.Pair;
1413
+ pair.setKey(key);
1414
+ bucket.push(pair);
1415
+ return pair;
1416
+ },
1417
+
1418
+ rassoc: function(value) {
1419
+ var key = this.key(value);
1420
+ return key ? this.assoc(key) : null;
1421
+ },
1422
+
1423
+ clear: function() {
1424
+ this._buckets = {};
1425
+ this.length = this.size = 0;
1426
+ },
1427
+
1428
+ compareByIdentity: function() {
1429
+ this._compareByIdentity = true;
1430
+ },
1431
+
1432
+ comparesByIdentity: function() {
1433
+ return !!this._compareByIdentity;
1434
+ },
1435
+
1436
+ setDefault: function(value) {
1437
+ this._default = value;
1438
+ return this;
1439
+ },
1440
+
1441
+ getDefault: function(key) {
1442
+ return JS.isFn(this._default)
1443
+ ? this._default(this, key)
1444
+ : (this._default || null);
1445
+ },
1446
+
1447
+ equals: function(other) {
1448
+ if (!JS.isType(other, JS.Hash) || this.length !== other.length)
1449
+ return false;
1450
+ var result = true;
1451
+ this.forEach(function(pair) {
1452
+ if (!result) return;
1453
+ var otherPair = other.assoc(pair.key);
1454
+ if (otherPair === null || !otherPair.hasValue(pair.value)) result = false;
1455
+ });
1456
+ return result;
1457
+ },
1458
+
1459
+ hash: function() {
1460
+ var hashes = [];
1461
+ this.forEach(function(pair) { hashes.push(pair.hash()) });
1462
+ return hashes.sort().join('');
1463
+ },
1464
+
1465
+ fetch: function(key, defaultValue) {
1466
+ var pair = this.assoc(key);
1467
+ if (pair) return pair.value;
1468
+
1469
+ if (defaultValue === undefined) throw new Error('key not found');
1470
+ if (JS.isFn(defaultValue)) return defaultValue(key);
1471
+ return defaultValue;
1472
+ },
1473
+
1474
+ forEachKey: function(block, context) {
1475
+ if (!block) return this.enumFor('forEachKey');
1476
+ block = JS.Enumerable.toFn(block);
1477
+
1478
+ this.forEach(function(pair) {
1479
+ block.call(context || null, pair.key);
1480
+ });
1481
+ return this;
1482
+ },
1483
+
1484
+ forEachPair: function(block, context) {
1485
+ if (!block) return this.enumFor('forEachPair');
1486
+ block = JS.Enumerable.toFn(block);
1487
+
1488
+ this.forEach(function(pair) {
1489
+ block.call(context || null, pair.key, pair.value);
1490
+ });
1491
+ return this;
1492
+ },
1493
+
1494
+ forEachValue: function(block, context) {
1495
+ if (!block) return this.enumFor('forEachValue');
1496
+ block = JS.Enumerable.toFn(block);
1497
+
1498
+ this.forEach(function(pair) {
1499
+ block.call(context || null, pair.value);
1500
+ });
1501
+ return this;
1502
+ },
1503
+
1504
+ get: function(key) {
1505
+ var pair = this.assoc(key);
1506
+ return pair ? pair.value : this.getDefault(key);
1507
+ },
1508
+
1509
+ hasKey: function(key) {
1510
+ return !!this.assoc(key);
1511
+ },
1512
+
1513
+ hasValue: function(value) {
1514
+ var has = false, ident = !!this._compareByIdentity;
1515
+ this.forEach(function(pair) {
1516
+ if ((value.equals && !ident) ? value.equals(pair.value) : value === pair.value)
1517
+ has = true;
1518
+ });
1519
+ return has;
1520
+ },
1521
+
1522
+ invert: function() {
1523
+ var hash = new this.klass;
1524
+ this.forEach(function(pair) {
1525
+ hash.store(pair.value, pair.key);
1526
+ });
1527
+ return hash;
1528
+ },
1529
+
1530
+ isEmpty: function() {
1531
+ for (var hash in this._buckets) {
1532
+ if (this._buckets.hasOwnProperty(hash) && this._buckets[hash].length > 0)
1533
+ return false;
1534
+ }
1535
+ return true;
1536
+ },
1537
+
1538
+ key: function(value) {
1539
+ var result = null;
1540
+ this.forEach(function(pair) {
1541
+ if (value.equals ? value.equals(pair.value) : (value === pair.value))
1542
+ result = pair.key;
1543
+ });
1544
+ return result;
1545
+ },
1546
+
1547
+ keys: function() {
1548
+ var keys = [];
1549
+ this.forEach(function(pair) { keys.push(pair.key) });
1550
+ return keys;
1551
+ },
1552
+
1553
+ merge: function(hash, block, context) {
1554
+ var newHash = new this.klass;
1555
+ newHash.update(this);
1556
+ newHash.update(hash, block, context);
1557
+ return newHash;
1558
+ },
1559
+
1560
+ rehash: function() {
1561
+ var temp = new this.klass;
1562
+ temp._buckets = this._buckets;
1563
+ this.clear();
1564
+ this.update(temp);
1565
+ },
1566
+
1567
+ remove: function(key, block) {
1568
+ if (block === undefined) block = null;
1569
+ var bucket, index, result;
1570
+
1571
+ bucket = this._bucketForKey(key);
1572
+ if (!bucket) return JS.isFn(block) ? this.fetch(key, block) : this.getDefault(key);
1573
+
1574
+ index = this._indexInBucket(bucket, key);
1575
+ if (index < 0) return JS.isFn(block) ? this.fetch(key, block) : this.getDefault(key);
1576
+
1577
+ result = bucket[index].value;
1578
+ bucket.splice(index, 1);
1579
+ this.size -= 1;
1580
+ this.length -= 1;
1581
+
1582
+ if (bucket.length === 0)
1583
+ delete this._buckets[this.klass.codeFor(key)];
1584
+
1585
+ return result;
1586
+ },
1587
+
1588
+ removeIf: function(block, context) {
1589
+ if (!block) return this.enumFor('removeIf');
1590
+ block = JS.Enumerable.toFn(block);
1591
+
1592
+ this.forEach(function(pair) {
1593
+ if (block.call(context || null, pair))
1594
+ this.remove(pair.key);
1595
+ }, this);
1596
+ return this;
1597
+ },
1598
+
1599
+ replace: function(hash) {
1600
+ this.clear();
1601
+ this.update(hash);
1602
+ },
1603
+
1604
+ shift: function() {
1605
+ var keys = this.keys();
1606
+ if (keys.length === 0) return this.getDefault();
1607
+ var pair = this.assoc(keys[0]);
1608
+ this.remove(pair.key);
1609
+ return pair;
1610
+ },
1611
+
1612
+ store: function(key, value) {
1613
+ this.assoc(key, true).setValue(value);
1614
+ return value;
1615
+ },
1616
+
1617
+ update: function(hash, block, context) {
1618
+ var blockGiven = JS.isFn(block);
1619
+ hash.forEach(function(pair) {
1620
+ var key = pair.key, value = pair.value;
1621
+ if (blockGiven && this.hasKey(key))
1622
+ value = block.call(context || null, key, this.get(key), value);
1623
+ this.store(key, value);
1624
+ }, this);
1625
+ },
1626
+
1627
+ values: function() {
1628
+ var values = [];
1629
+ this.forEach(function(pair) { values.push(pair.value) });
1630
+ return values;
1631
+ },
1632
+
1633
+ valuesAt: function() {
1634
+ var i = arguments.length, results = [];
1635
+ while (i--) results.push(this.get(arguments[i]));
1636
+ return results;
1637
+ }
1638
+ });
1639
+
1640
+ JS.Hash.include({
1641
+ includes: JS.Hash.instanceMethod('hasKey'),
1642
+ index: JS.Hash.instanceMethod('key'),
1643
+ put: JS.Hash.instanceMethod('store')
1644
+ }, true);
1645
+
1646
+
1647
+ JS.Set = new JS.Class('Set', {
1648
+ extend: {
1649
+ forEach: function(list, block, context) {
1650
+ if (!list || !block) return;
1651
+ if (list.forEach) return list.forEach(block, context);
1652
+ for (var i = 0, n = list.length; i < n; i++) {
1653
+ if (list[i] !== undefined)
1654
+ block.call(context || null, list[i], i);
1655
+ }
1656
+ }
1657
+ },
1658
+
1659
+ include: JS.Enumerable || {},
1660
+
1661
+ initialize: function(list, block, context) {
1662
+ this.clear();
1663
+ if (block) this.klass.forEach(list, function(item) {
1664
+ this.add(block.call(context || null, item));
1665
+ }, this);
1666
+ else this.merge(list);
1667
+ },
1668
+
1669
+ forEach: function(block, context) {
1670
+ if (!block) return this.enumFor('forEach');
1671
+ block = JS.Enumerable.toFn(block);
1672
+
1673
+ this.klass.forEach(this._members, block, context);
1674
+ return this;
1675
+ },
1676
+
1677
+ add: function(item) {
1678
+ if (this.contains(item)) return false;
1679
+ this._members.push(item);
1680
+ this.length = this.size = this._members.length;
1681
+ return true;
1682
+ },
1683
+
1684
+ classify: function(block, context) {
1685
+ if (!block) return this.enumFor('classify');
1686
+ block = JS.Enumerable.toFn(block);
1687
+
1688
+ var classes = new JS.Hash();
1689
+ this.forEach(function(item) {
1690
+ var value = block.call(context || null, item);
1691
+ if (!classes.hasKey(value)) classes.store(value, new this.klass);
1692
+ classes.get(value).add(item);
1693
+ }, this);
1694
+ return classes;
1695
+ },
1696
+
1697
+ clear: function() {
1698
+ this._members = [];
1699
+ this.length = this.size = 0;
1700
+ },
1701
+
1702
+ complement: function(other) {
1703
+ var set = new this.klass;
1704
+ this.klass.forEach(other, function(item) {
1705
+ if (!this.contains(item)) set.add(item);
1706
+ }, this);
1707
+ return set;
1708
+ },
1709
+
1710
+ contains: function(item) {
1711
+ return this._indexOf(item) !== -1;
1712
+ },
1713
+
1714
+ difference: function(other) {
1715
+ other = JS.isType(other, JS.Set) ? other : new JS.Set(other);
1716
+ var set = new this.klass;
1717
+ this.forEach(function(item) {
1718
+ if (!other.contains(item)) set.add(item);
1719
+ });
1720
+ return set;
1721
+ },
1722
+
1723
+ divide: function(block, context) {
1724
+ if (!block) return this.enumFor('divide');
1725
+ block = JS.Enumerable.toFn(block);
1726
+
1727
+ var classes = this.classify(block, context),
1728
+ sets = new this.klass;
1729
+
1730
+ classes.forEachValue(sets.method('add'));
1731
+ return sets;
1732
+ },
1733
+
1734
+ equals: function(other) {
1735
+ if (this.length !== other.length || !JS.isType(other, JS.Set)) return false;
1736
+ var result = true;
1737
+ this.forEach(function(item) {
1738
+ if (!result) return;
1739
+ if (!other.contains(item)) result = false;
1740
+ });
1741
+ return result;
1742
+ },
1743
+
1744
+ hash: function() {
1745
+ var hashes = [];
1746
+ this.forEach(function(object) { hashes.push(JS.Hash.codeFor(object)) });
1747
+ return hashes.sort().join('');
1748
+ },
1749
+
1750
+ flatten: function(set) {
1751
+ var copy = new this.klass;
1752
+ copy._members = this._members;
1753
+ if (!set) { set = this; set.clear(); }
1754
+ copy.forEach(function(item) {
1755
+ if (JS.isType(item, JS.Set)) item.flatten(set);
1756
+ else set.add(item);
1757
+ });
1758
+ return set;
1759
+ },
1760
+
1761
+ intersection: function(other) {
1762
+ var set = new this.klass;
1763
+ this.klass.forEach(other, function(item) {
1764
+ if (this.contains(item)) set.add(item);
1765
+ }, this);
1766
+ return set;
1767
+ },
1768
+
1769
+ isEmpty: function() {
1770
+ return this._members.length === 0;
1771
+ },
1772
+
1773
+ isProperSubset: function(other) {
1774
+ return this._members.length < other._members.length && this.isSubset(other);
1775
+ },
1776
+
1777
+ isProperSuperset: function(other) {
1778
+ return this._members.length > other._members.length && this.isSuperset(other);
1779
+ },
1780
+
1781
+ isSubset: function(other) {
1782
+ var result = true;
1783
+ this.forEach(function(item) {
1784
+ if (!result) return;
1785
+ if (!other.contains(item)) result = false;
1786
+ });
1787
+ return result;
1788
+ },
1789
+
1790
+ isSuperset: function(other) {
1791
+ return other.isSubset(this);
1792
+ },
1793
+
1794
+ merge: function(list) {
1795
+ this.klass.forEach(list, function(item) { this.add(item) }, this);
1796
+ },
1797
+
1798
+ product: function(other) {
1799
+ var pairs = new JS.Set;
1800
+ this.forEach(function(item) {
1801
+ this.klass.forEach(other, function(partner) {
1802
+ pairs.add([item, partner]);
1803
+ });
1804
+ }, this);
1805
+ return pairs;
1806
+ },
1807
+
1808
+ rebuild: function() {
1809
+ var members = this._members;
1810
+ this.clear();
1811
+ this.merge(members);
1812
+ },
1813
+
1814
+ remove: function(item) {
1815
+ var index = this._indexOf(item);
1816
+ if (index === -1) return;
1817
+ this._members.splice(index, 1);
1818
+ this.length = this.size = this._members.length;
1819
+ },
1820
+
1821
+ removeIf: function(block, context) {
1822
+ if (!block) return this.enumFor('removeIf');
1823
+ block = JS.Enumerable.toFn(block);
1824
+
1825
+ var members = this._members,
1826
+ i = members.length;
1827
+
1828
+ while (i--) {
1829
+ if (block.call(context || null, members[i]))
1830
+ this.remove(members[i]);
1831
+ }
1832
+ return this;
1833
+ },
1834
+
1835
+ replace: function(other) {
1836
+ this.clear();
1837
+ this.merge(other);
1838
+ },
1839
+
1840
+ subtract: function(list) {
1841
+ this.klass.forEach(list, function(item) {
1842
+ this.remove(item);
1843
+ }, this);
1844
+ },
1845
+
1846
+ union: function(other) {
1847
+ var set = new this.klass;
1848
+ set.merge(this);
1849
+ set.merge(other);
1850
+ return set;
1851
+ },
1852
+
1853
+ xor: function(other) {
1854
+ var set = new JS.Set(other);
1855
+ this.forEach(function(item) {
1856
+ set[set.contains(item) ? 'remove' : 'add'](item);
1857
+ });
1858
+ return set;
1859
+ },
1860
+
1861
+ _indexOf: function(item) {
1862
+ var i = this._members.length,
1863
+ equal = JS.Enumerable.areEqual;
1864
+
1865
+ while (i--) {
1866
+ if (equal(item, this._members[i])) return i;
1867
+ }
1868
+ return -1;
1869
+ }
1870
+ });
1871
+
1872
+ JS.Set.include({
1873
+ n: JS.Set.instanceMethod('intersection'),
1874
+ u: JS.Set.instanceMethod('union'),
1875
+ x: JS.Set.instanceMethod('product')
1876
+ }, false);
1877
+
1878
+ JS.SortedSet = new JS.Class('SortedSet', JS.Set, {
1879
+ extend: {
1880
+ compare: function(one, another) {
1881
+ return JS.isType(one, Object)
1882
+ ? one.compareTo(another)
1883
+ : (one < another ? -1 : (one > another ? 1 : 0));
1884
+ }
1885
+ },
1886
+
1887
+ add: function(item) {
1888
+ var point = this._indexOf(item, true);
1889
+ if (point === null) return;
1890
+ this._members.splice(point, 0, item);
1891
+ this.length = this.size = this._members.length;
1892
+ },
1893
+
1894
+ _indexOf: function(item, insertionPoint) {
1895
+ var items = this._members,
1896
+ n = items.length,
1897
+ i = 0,
1898
+ d = n,
1899
+ compare = this.klass.compare,
1900
+ equal = JS.Enumerable.areEqual,
1901
+ found;
1902
+
1903
+ if (n === 0) return insertionPoint ? 0 : -1;
1904
+
1905
+ if (compare(item, items[0]) < 1) { d = 0; i = 0; }
1906
+ if (compare(item, items[n-1]) > 0) { d = 0; i = n; }
1907
+
1908
+ while (!equal(item, items[i]) && d > 0.5) {
1909
+ d = d / 2;
1910
+ i += (compare(item, items[i]) > 0 ? 1 : -1) * Math.round(d);
1911
+ if (i > 0 && compare(item, items[i-1]) > 0 && compare(item, items[i]) < 1) d = 0;
1912
+ }
1913
+
1914
+ // The pointer will end up at the start of any homogenous section. Step
1915
+ // through the section until we find the needle or until the section ends.
1916
+ while (items[i] && !equal(item, items[i]) &&
1917
+ compare(item, items[i]) === 0) i += 1;
1918
+
1919
+ found = equal(item, items[i]);
1920
+ return insertionPoint
1921
+ ? (found ? null : i)
1922
+ : (found ? i : -1);
1923
+ }
1924
+ });
1925
+
1926
+ JS.HashSet = new JS.Class('HashSet', JS.Set, {
1927
+ forEach: function(block, context) {
1928
+ if (!block) return this.enumFor('forEach');
1929
+ block = JS.Enumerable.toFn(block);
1930
+
1931
+ this._members.forEachKey(block, context);
1932
+ return this;
1933
+ },
1934
+
1935
+ add: function(item) {
1936
+ if (this.contains(item)) return false;
1937
+ this._members.store(item, true);
1938
+ this.length = this.size = this._members.length;
1939
+ return true;
1940
+ },
1941
+
1942
+ clear: function() {
1943
+ this._members = new JS.Hash();
1944
+ this.size = this.length = 0;
1945
+ },
1946
+
1947
+ contains: function(item) {
1948
+ return this._members.hasKey(item);
1949
+ },
1950
+
1951
+ rebuild: function() {
1952
+ this._members.rehash();
1953
+ this.length = this.size = this._members.length;
1954
+ },
1955
+
1956
+ remove: function(item) {
1957
+ this._members.remove(item);
1958
+ this.length = this.size = this._members.length;
1959
+ },
1960
+
1961
+ removeIf: function(block, context) {
1962
+ if (!block) return this.enumFor('removeIf');
1963
+ block = JS.Enumerable.toFn(block);
1964
+
1965
+ this._members.removeIf(function(pair) {
1966
+ return block.call(context || null, pair.key);
1967
+ });
1968
+ this.length = this.size = this._members.length;
1969
+ return this;
1970
+ }
1971
+ });
1972
+
1973
+ JS.Enumerable.include({
1974
+ toSet: function(klass, block, context) {
1975
+ klass = klass || JS.Set;
1976
+ return new klass(this, block, context);
1977
+ }
1978
+ }, true);
1979
+
1980
+
1981
+ JS.Observable = new JS.Module('Observable', {
1982
+ extend: {
1983
+ DEFAULT_METHOD: 'update'
1984
+ },
1985
+
1986
+ addObserver: function(observer, context) {
1987
+ (this.__observers__ = this.__observers__ || []).push({_block: observer, _context: context || null});
1988
+ },
1989
+
1990
+ removeObserver: function(observer, context) {
1991
+ this.__observers__ = this.__observers__ || [];
1992
+ context = context || null;
1993
+ var i = this.countObservers();
1994
+ while (i--) {
1995
+ if (this.__observers__[i]._block === observer && this.__observers__[i]._context === context) {
1996
+ this.__observers__.splice(i,1);
1997
+ return;
1998
+ }
1999
+ }
2000
+ },
2001
+
2002
+ removeObservers: function() {
2003
+ this.__observers__ = [];
2004
+ },
2005
+
2006
+ countObservers: function() {
2007
+ return (this.__observers__ = this.__observers__ || []).length;
2008
+ },
2009
+
2010
+ notifyObservers: function() {
2011
+ if (!this.isChanged()) return;
2012
+ var i = this.countObservers(), observer, block, context;
2013
+ while (i--) {
2014
+ observer = this.__observers__[i];
2015
+ block = observer._block;
2016
+ context = observer._context;
2017
+ if (JS.isFn(block)) block.apply(context || null, arguments);
2018
+ else block[context || JS.Observable.DEFAULT_METHOD].apply(block, arguments);
2019
+ }
2020
+ },
2021
+
2022
+ setChanged: function(state) {
2023
+ this.__changed__ = !(state === false);
2024
+ },
2025
+
2026
+ isChanged: function() {
2027
+ if (this.__changed__ === undefined) this.__changed__ = true;
2028
+ return !!this.__changed__;
2029
+ }
2030
+ });
2031
+
2032
+ JS.Observable.include({
2033
+ subscribe: JS.Observable.instanceMethod('addObserver'),
2034
+ unsubscribe: JS.Observable.instanceMethod('removeObserver')
2035
+ }, true);
2036
+
2037
+
2038
+ JS.Forwardable = new JS.Module('Forwardable', {
2039
+ defineDelegator: function(subject, method, alias, resolve) {
2040
+ alias = alias || method;
2041
+ this.define(alias, function() {
2042
+ var object = this[subject],
2043
+ property = object[method];
2044
+
2045
+ return JS.isFn(property)
2046
+ ? property.apply(object, arguments)
2047
+ : property;
2048
+ }, resolve !== false);
2049
+ },
2050
+
2051
+ defineDelegators: function() {
2052
+ var methods = JS.array(arguments),
2053
+ subject = methods.shift(),
2054
+ i = methods.length;
2055
+
2056
+ while (i--) this.defineDelegator(subject, methods[i], methods[i], false);
2057
+ this.resolve();
2058
+ }
2059
+ });
2060
+
2061
+
2062
+ JS.ConstantScope = new JS.Module('ConstantScope', {
2063
+ extend: {
2064
+ included: function(base) {
2065
+ base.__consts__ = new JS.Module();
2066
+ base.extend(this.ClassMethods);
2067
+
2068
+ base.include(base.__consts__);
2069
+ base.extend(base.__consts__);
2070
+
2071
+ base.include(base.__mod__.__fns__);
2072
+ base.extend(base.__eigen__().__fns__);
2073
+ },
2074
+
2075
+ ClassMethods: new JS.Module({
2076
+ extend: function() {
2077
+ var constants = JS.ConstantScope.extract(arguments[0], this);
2078
+ this.__consts__.include(constants);
2079
+ this.callSuper();
2080
+ },
2081
+
2082
+ include: function() {
2083
+ var constants = JS.ConstantScope.extract(arguments[0], this);
2084
+ this.__consts__.include(constants);
2085
+ this.callSuper();
2086
+ }
2087
+ }),
2088
+
2089
+ extract: function(inclusions, base) {
2090
+ if (!inclusions) return null;
2091
+ if (JS.isType(inclusions, JS.Module)) return null;
2092
+ var constants = {}, key, object;
2093
+ for (key in inclusions) {
2094
+
2095
+ if (!/^[A-Z]/.test(key)) continue;
2096
+
2097
+ object = inclusions[key];
2098
+ constants[key] = object;
2099
+ delete inclusions[key];
2100
+
2101
+ if (JS.isType(object, JS.Module)) {
2102
+ object.include(this);
2103
+ object.__consts__.include(base.__consts__);
2104
+ }
2105
+ }
2106
+ return constants;
2107
+ }
2108
+ }
2109
+ });
2110
+
2111
+
2112
+ JS.Decorator = new JS.Class('Decorator', {
2113
+ initialize: function(decoree, methods) {
2114
+ var decorator = new JS.Class(),
2115
+ delegators = {},
2116
+ method, func;
2117
+
2118
+ for (method in decoree.prototype) {
2119
+ func = decoree.prototype[method];
2120
+ if (JS.isFn(func) && func !== decoree) func = this.klass.delegate(method);
2121
+ delegators[method] = func;
2122
+ }
2123
+
2124
+ decorator.include(new JS.Module(delegators), false);
2125
+ decorator.include(this.klass.InstanceMethods, false);
2126
+ decorator.include(methods, true);
2127
+ return decorator;
2128
+ },
2129
+
2130
+ extend: {
2131
+ delegate: function(name) {
2132
+ return function() {
2133
+ return this.component[name].apply(this.component, arguments);
2134
+ };
2135
+ },
2136
+
2137
+ InstanceMethods: new JS.Module({
2138
+ initialize: function(component) {
2139
+ this.component = component;
2140
+ this.klass = this.constructor = component.klass;
2141
+ var method, func;
2142
+ for (method in component) {
2143
+ if (this[method]) continue;
2144
+ func = component[method];
2145
+ if (JS.isFn(func)) func = JS.Decorator.delegate(method);
2146
+ this[method] = func;
2147
+ }
2148
+ },
2149
+
2150
+ extend: function(source) {
2151
+ this.component.extend(source);
2152
+ var method, func;
2153
+ for (method in source) {
2154
+ func = source[method];
2155
+ if (JS.isFn(func)) func = JS.Decorator.delegate(method);
2156
+ this[method] = func;
2157
+ }
2158
+ }
2159
+ })
2160
+ }
2161
+ });
2162
+
2163
+
2164
+ if (JS.Proxy === undefined) JS.Proxy = {};
2165
+
2166
+ JS.Proxy.Virtual = new JS.Class('Proxy.Virtual', {
2167
+ initialize: function(klass) {
2168
+ var bridge = function() {},
2169
+ proxy = new JS.Class(),
2170
+ delegators = {},
2171
+ method, func;
2172
+
2173
+ bridge.prototype = klass.prototype;
2174
+
2175
+ for (method in klass.prototype) {
2176
+ func = klass.prototype[method];
2177
+ if (JS.isFn(func) && func !== klass) func = this.klass.forward(method);
2178
+ delegators[method] = func;
2179
+ }
2180
+
2181
+ proxy.include({
2182
+ initialize: function() {
2183
+ var args = arguments,
2184
+ subject = null;
2185
+
2186
+ this.__getSubject__ = function() {
2187
+ subject = new bridge;
2188
+ klass.apply(subject, args);
2189
+ return (this.__getSubject__ = function() { return subject; })();
2190
+ };
2191
+ },
2192
+ klass: klass,
2193
+ constructor: klass
2194
+ }, false);
2195
+
2196
+ proxy.include(new JS.Module(delegators), false);
2197
+ proxy.include(this.klass.InstanceMethods, true);
2198
+ return proxy;
2199
+ },
2200
+
2201
+ extend: {
2202
+ forward: function(name) {
2203
+ return function() {
2204
+ var subject = this.__getSubject__();
2205
+ return subject[name].apply(subject, arguments);
2206
+ };
2207
+ },
2208
+
2209
+ InstanceMethods: new JS.Module({
2210
+ extend: function(source) {
2211
+ this.__getSubject__().extend(source);
2212
+ var method, func;
2213
+ for (method in source) {
2214
+ func = source[method];
2215
+ if (JS.isFn(func)) func = JS.Proxy.Virtual.forward(method);
2216
+ this[method] = func;
2217
+ }
2218
+ }
2219
+ })
2220
+ }
2221
+ });
2222
+
2223
+
2224
+ JS.Command = new JS.Class('Command', {
2225
+ initialize: function(functions) {
2226
+ if (JS.isFn(functions))
2227
+ functions = {execute: functions};
2228
+ this._functions = functions;
2229
+ this._stack = this._functions.stack || null;
2230
+ },
2231
+
2232
+ execute: function(push) {
2233
+ if (this._stack) this._stack._restart();
2234
+ var exec = this._functions.execute;
2235
+ if (exec) exec.apply(this);
2236
+ if (this._stack && push !== false) this._stack.push(this);
2237
+ },
2238
+
2239
+ undo: function() {
2240
+ var exec = this._functions.undo;
2241
+ if (exec) exec.apply(this);
2242
+ },
2243
+
2244
+ extend: {
2245
+ Stack: new JS.Class({
2246
+ include: [JS.Observable || {}, JS.Enumerable || {}],
2247
+
2248
+ initialize: function(options) {
2249
+ options = options || {};
2250
+ this._redo = options.redo || null;
2251
+ this.clear();
2252
+ },
2253
+
2254
+ forEach: function(block, context) {
2255
+ if (!block) return this.enumFor('forEach');
2256
+ block = JS.Enumerable.toFn(block);
2257
+
2258
+ for (var i = 0, n = this._stack.length; i < n; i++) {
2259
+ if (this._stack[i] !== undefined)
2260
+ block.call(context || null, this._stack[i], i);
2261
+ }
2262
+ return this;
2263
+ },
2264
+
2265
+ clear: function() {
2266
+ this._stack = [];
2267
+ this.length = this.pointer = 0;
2268
+ },
2269
+
2270
+ _restart: function() {
2271
+ if (this.pointer === 0 && this._redo && this._redo.execute)
2272
+ this._redo.execute();
2273
+ },
2274
+
2275
+ push: function(command) {
2276
+ this._stack.splice(this.pointer, this.length);
2277
+ this._stack.push(command);
2278
+ this.length = this.pointer = this._stack.length;
2279
+ if (this.notifyObservers) this.notifyObservers(this);
2280
+ },
2281
+
2282
+ stepTo: function(position) {
2283
+ if (position < 0 || position > this.length) return;
2284
+ var i, n;
2285
+
2286
+ switch (true) {
2287
+ case position > this.pointer :
2288
+ for (i = this.pointer, n = position; i < n; i++)
2289
+ this._stack[i].execute(false);
2290
+ break;
2291
+
2292
+ case position < this.pointer :
2293
+ if (this._redo && this._redo.execute) {
2294
+ this._redo.execute();
2295
+ for (i = 0, n = position; i < n; i++)
2296
+ this._stack[i].execute(false);
2297
+ } else {
2298
+ for (i = 0, n = this.pointer - position; i < n; i++)
2299
+ this._stack[this.pointer - i - 1].undo();
2300
+ }
2301
+ break;
2302
+ }
2303
+ this.pointer = position;
2304
+ if (this.notifyObservers) this.notifyObservers(this);
2305
+ },
2306
+
2307
+ undo: function() {
2308
+ this.stepTo(this.pointer - 1);
2309
+ },
2310
+
2311
+ redo: function() {
2312
+ this.stepTo(this.pointer + 1);
2313
+ }
2314
+ })
2315
+ }
2316
+ });
2317
+
2318
+
2319
+ JS.State = new JS.Module('State', {
2320
+ __getState__: function(state) {
2321
+ return (typeof state === 'object' && state) ||
2322
+ (typeof state === 'string' && ((this.states || {})[state] || {})) ||
2323
+ {};
2324
+ },
2325
+
2326
+ setState: function(state) {
2327
+ this.__state__ = this.__getState__(state);
2328
+ JS.State.addMethods(this.__state__, this.klass);
2329
+ },
2330
+
2331
+ inState: function() {
2332
+ var i = arguments.length;
2333
+ while (i--) {
2334
+ if (this.__state__ === this.__getState__(arguments[i])) return true;
2335
+ }
2336
+ return false;
2337
+ },
2338
+
2339
+ extend: {
2340
+ stub: function() { return this; },
2341
+
2342
+ buildStubs: function(stubs, collection, states) {
2343
+ var state, method;
2344
+ for (state in states) {
2345
+ collection[state] = {};
2346
+ for (method in states[state]) stubs[method] = this.stub;
2347
+ } },
2348
+
2349
+ findStates: function(collections, name) {
2350
+ var i = collections.length, results = [];
2351
+ while (i--) {
2352
+ if (collections[i].hasOwnProperty(name))
2353
+ results.push(collections[i][name]);
2354
+ }
2355
+ return results;
2356
+ },
2357
+
2358
+ buildCollection: function(module, states) {
2359
+ var stubs = {},
2360
+ collection = {},
2361
+ superstates = module.lookup('states'),
2362
+ state, klass, methods, name, mixins, i, n;
2363
+
2364
+ this.buildStubs(stubs, collection, states);
2365
+
2366
+ for (i = 0, n = superstates.length; i < n; i++)
2367
+ this.buildStubs(stubs, collection, superstates[i]);
2368
+
2369
+ for (state in collection) {
2370
+ klass = new JS.Class(states[state]);
2371
+ mixins = this.findStates(superstates, state);
2372
+
2373
+ i = mixins.length;
2374
+ while (i--) klass.include(mixins[i].klass);
2375
+
2376
+ methods = {};
2377
+ for (name in stubs) { if (!klass.prototype[name]) methods[name] = stubs[name]; }
2378
+ klass.include(methods);
2379
+ collection[state] = new klass;
2380
+ }
2381
+ if (module.__res__) this.addMethods(stubs, module.__res__.klass);
2382
+ return collection;
2383
+ },
2384
+
2385
+ addMethods: function(state, klass) {
2386
+ if (!klass) return;
2387
+
2388
+ var methods = {},
2389
+ p = klass.prototype,
2390
+ method;
2391
+
2392
+ for (method in state) {
2393
+ if (p[method]) continue;
2394
+ p[method] = klass.__mod__.__fns__[method] = this.wrapped(method);
2395
+ }
2396
+ },
2397
+
2398
+ wrapped: function(method) {
2399
+ return function() {
2400
+ var func = (this.__state__ || {})[method];
2401
+ return func ? func.apply(this, arguments): this;
2402
+ };
2403
+ }
2404
+ }
2405
+ });
2406
+
2407
+ JS.Module.include({define: (function(wrapped) {
2408
+ return function(name, block) {
2409
+ if (name === 'states' && typeof block === 'object')
2410
+ arguments[1] = JS.State.buildCollection(this, block);
2411
+ return wrapped.apply(this, arguments);
2412
+ };
2413
+ })(JS.Module.prototype.define)}, true);
2414
+
2415
+
2416
+ JS.StackTrace = new JS.Module('StackTrace', {
2417
+ extend: {
2418
+ included: function(base) {
2419
+ var module = base.__mod__ || base,
2420
+ self = this,
2421
+ method;
2422
+
2423
+ module.extend({define: function(name, func) {
2424
+ if (!JS.isFn(func)) return this.callSuper();
2425
+ var wrapper = self.wrap(func, module, name);
2426
+ return this.callSuper(name, wrapper);
2427
+ } });
2428
+
2429
+ for (method in module.__fns__)
2430
+ module.define(method, module.__fns__[method], false);
2431
+ module.resolve();
2432
+
2433
+ if (!module.__nom__) setTimeout(function() {
2434
+ module.__nom__ = self.nameOf(base);
2435
+ }, 1);
2436
+ },
2437
+
2438
+ nameOf: function(object, root) {
2439
+ var results = [], i, n, field, l;
2440
+
2441
+ if (JS.isType(object, Array)) {
2442
+ for (i = 0, n = object.length; i < n; i++)
2443
+ results.push(this.nameOf(object[i]));
2444
+ return results;
2445
+ }
2446
+
2447
+ if (object.__nom__) return object.__nom__;
2448
+
2449
+ field = [{name: null, o: root || this.root}];
2450
+ l = 0;
2451
+ while (typeof field === 'object' && l < this.maxDepth) {
2452
+ l += 1;
2453
+ field = this.descend(field, object);
2454
+ }
2455
+ if (typeof field == 'string') {
2456
+ field = field.replace(/\.prototype\./g, '#');
2457
+ object.__nom__ = field;
2458
+ if (object.__meta__) object.__meta__.__nom__ = field + '.__meta__';
2459
+ }
2460
+ return object.__nom__;
2461
+ },
2462
+
2463
+ descend: function(list, needle) {
2464
+ var results = [],
2465
+ n = list.length,
2466
+ i = n,
2467
+ key, item, name;
2468
+
2469
+ while (i--) {
2470
+ item = list[i];
2471
+ if (n > 1 && JS.indexOf(this.excluded, item.o) !== -1) continue;
2472
+ if (JS.isType(item.o, Array)) continue;
2473
+ name = item.name ? item.name + '.' : '';
2474
+ for (key in item.o) {
2475
+ if (needle && item.o[key] === needle) return name + key;
2476
+ results.push({name: name + key, o: item.o[key]});
2477
+ }
2478
+ }
2479
+ return results;
2480
+ },
2481
+
2482
+ root: this,
2483
+ excluded: [],
2484
+ maxDepth: 8,
2485
+ logLevel: 'full',
2486
+
2487
+ stack: new JS.Singleton({
2488
+ _list: [],
2489
+
2490
+ indent: function() {
2491
+ var indent = '',
2492
+ n = this._list.length;
2493
+
2494
+ while (n--) indent += '| ';
2495
+ return indent;
2496
+ },
2497
+
2498
+ push: function(name, object, args) {
2499
+ if (JS.StackTrace.logLevel === 'full') window.console &&
2500
+ console.log(this.indent() + name + '(', args, ')');
2501
+ this._list.push({name: name, object: object, args: args});
2502
+ },
2503
+
2504
+ pop: function(result) {
2505
+ var name = this._list.pop().name;
2506
+ if (JS.StackTrace.logLevel === 'full') window.console &&
2507
+ console.log(this.indent() + name + '() --> ', result);
2508
+ return name;
2509
+ },
2510
+
2511
+ top: function() {
2512
+ return this._list[this._list.length - 1] || {};
2513
+ },
2514
+
2515
+ backtrace: function() {
2516
+ var i = this._list.length, item;
2517
+ while (i--) {
2518
+ item = this._list[i];
2519
+ window.console && console.log(item.name, 'in', item.object, '(', item.args, ')');
2520
+ }
2521
+ }
2522
+ }),
2523
+
2524
+ flush: function() {
2525
+ this.stack._list = [];
2526
+ },
2527
+
2528
+ print: function() {
2529
+ this.stack.backtrace();
2530
+ },
2531
+
2532
+ wrap: function(func, module, name) {
2533
+ var self = JS.StackTrace;
2534
+ var wrapper = function() {
2535
+ var result, fullName = self.nameOf(module) + '#' + name;
2536
+ self.stack.push(fullName, this, arguments);
2537
+
2538
+ if (self.logLevel === 'errors') {
2539
+ try { result = func.apply(this, arguments); }
2540
+ catch (e) {
2541
+ if (e.logged) throw e;
2542
+ e.logged = true;
2543
+ window.console && console.error(e, 'thrown by', self.stack.top().name + '. Backtrace:');
2544
+ self.print();
2545
+ self.flush();
2546
+ throw e;
2547
+ }
2548
+ } else {
2549
+ result = func.apply(this, arguments);
2550
+ }
2551
+
2552
+ self.stack.pop(result);
2553
+ return result;
2554
+ };
2555
+ wrapper.toString = function() { return func.toString() };
2556
+ return wrapper;
2557
+ }
2558
+ }
2559
+ });
2560
+
2561
+ (function() {
2562
+ var module = JS.StackTrace, key;
2563
+ for (key in module.root) {
2564
+ if (key !== 'JS') module.excluded.push(module.root[key]);
2565
+ }
2566
+ })();
2567
+
2568
+
2569
+ JS.Ruby = function(klass, define) {
2570
+ define.call(new JS.Ruby.ClassBuilder(klass));
2571
+ };
2572
+
2573
+ JS.extend(JS.Ruby, {
2574
+ extendDSL: function(builder, source) {
2575
+ for (var method in source) {
2576
+ if (builder[method] || !JS.isFn(source[method])) continue;
2577
+ this.addMethod(builder, source, method);
2578
+ }
2579
+ },
2580
+
2581
+ addMethod: function(builder, source, method) {
2582
+ builder[method] = function() {
2583
+ var result = source[method].apply(source, arguments);
2584
+ JS.Ruby.extendDSL(builder, source);
2585
+ return result;
2586
+ };
2587
+ },
2588
+
2589
+ alias: function(object, builder) {
2590
+ return function(newName, oldName) {
2591
+ var old = object[oldName];
2592
+ if (old !== undefined) this.def(newName, old);
2593
+ if (builder) JS.Ruby.extendDSL(builder, object);
2594
+ };
2595
+ },
2596
+
2597
+ ClassBuilder: function(klass) {
2598
+ this.def = klass.method('define');
2599
+ this.alias = JS.Ruby.alias(klass.prototype);
2600
+
2601
+ this.self = {
2602
+ def: JS.bind(function(name, method) {
2603
+ var def = {}; def[name] = method;
2604
+ klass.extend(def);
2605
+ JS.Ruby.extendDSL(this, klass);
2606
+ }, this),
2607
+ alias: JS.Ruby.alias(klass, this)
2608
+ };
2609
+
2610
+ JS.Ruby.extendDSL(this, klass);
2611
+ }
2612
+ });