aleph_analytics 0.0.0.alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (527) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +0 -0
  3. data/Gemfile +70 -0
  4. data/Gemfile.lock +489 -0
  5. data/LICENSE +21 -0
  6. data/Procfile +2 -0
  7. data/README.md +1 -0
  8. data/ROADMAP.md +7 -0
  9. data/Rakefile +9 -0
  10. data/app/assets/fonts/octicons-local.ttf +0 -0
  11. data/app/assets/fonts/octicons.eot +0 -0
  12. data/app/assets/fonts/octicons.svg +183 -0
  13. data/app/assets/fonts/octicons.ttf +0 -0
  14. data/app/assets/fonts/octicons.woff +0 -0
  15. data/app/assets/javascripts/angular/aleph.js.es6 +90 -0
  16. data/app/assets/javascripts/angular/config/schema_completer_config.js.es6 +71 -0
  17. data/app/assets/javascripts/angular/controllers/alerts/alert_index_controller.js.es6 +16 -0
  18. data/app/assets/javascripts/angular/controllers/alerts/alert_show_controller.js.es6 +99 -0
  19. data/app/assets/javascripts/angular/controllers/controllers.js.es6 +65 -0
  20. data/app/assets/javascripts/angular/controllers/query/query_index_controller.js.es6 +80 -0
  21. data/app/assets/javascripts/angular/controllers/query/query_repl_controller.js.es6 +147 -0
  22. data/app/assets/javascripts/angular/controllers/query/query_show_controller.js.es6 +43 -0
  23. data/app/assets/javascripts/angular/controllers/schema/schema_index_controller.js.es6 +61 -0
  24. data/app/assets/javascripts/angular/controllers/snippet/snippet_index_controller.js.es6 +80 -0
  25. data/app/assets/javascripts/angular/directives/directives.js.es6 +30 -0
  26. data/app/assets/javascripts/angular/directives/query/query_details_directive.js.es6 +87 -0
  27. data/app/assets/javascripts/angular/directives/query/query_version_sidebar_directive.js.es6 +65 -0
  28. data/app/assets/javascripts/angular/directives/result/result_directive.js.es6 +59 -0
  29. data/app/assets/javascripts/angular/directives/result/results_directive.js.es6 +30 -0
  30. data/app/assets/javascripts/angular/directives/visualization_directive.js.es6 +101 -0
  31. data/app/assets/javascripts/angular/filters/filters.js.es6 +27 -0
  32. data/app/assets/javascripts/angular/services/alert/alert.js.es6 +51 -0
  33. data/app/assets/javascripts/angular/services/alert/alert_resource.js.es6 +10 -0
  34. data/app/assets/javascripts/angular/services/lib/ace_completers.js.es6 +29 -0
  35. data/app/assets/javascripts/angular/services/lib/ace_sql_parse.js.es6 +156 -0
  36. data/app/assets/javascripts/angular/services/lib/action_handler.js.es6 +73 -0
  37. data/app/assets/javascripts/angular/services/lib/alert_flash.js.es6 +30 -0
  38. data/app/assets/javascripts/angular/services/lib/default_ace_configurator_service.js.es6 +74 -0
  39. data/app/assets/javascripts/angular/services/lib/github_url_service.js.es6 +53 -0
  40. data/app/assets/javascripts/angular/services/lib/keyword_completer.js.es6 +36 -0
  41. data/app/assets/javascripts/angular/services/lib/local_resource.js.es6 +20 -0
  42. data/app/assets/javascripts/angular/services/lib/lock_service.js.es6 +48 -0
  43. data/app/assets/javascripts/angular/services/lib/locking_poll_service.js.es6 +42 -0
  44. data/app/assets/javascripts/angular/services/lib/matcher_runner.js.es6 +65 -0
  45. data/app/assets/javascripts/angular/services/lib/navigation_guard.js.es6 +45 -0
  46. data/app/assets/javascripts/angular/services/lib/open_repl_service.js.es6 +56 -0
  47. data/app/assets/javascripts/angular/services/lib/page_title_manager.js.es6 +38 -0
  48. data/app/assets/javascripts/angular/services/lib/pagination.js.es6 +114 -0
  49. data/app/assets/javascripts/angular/services/lib/pagination_components.js.es6 +91 -0
  50. data/app/assets/javascripts/angular/services/lib/parameter_methods.js.es6 +35 -0
  51. data/app/assets/javascripts/angular/services/lib/role_model.js.es6 +21 -0
  52. data/app/assets/javascripts/angular/services/lib/schema_completer.js.es6 +56 -0
  53. data/app/assets/javascripts/angular/services/lib/selection_tag_input.js.es6 +42 -0
  54. data/app/assets/javascripts/angular/services/lib/server_configurations.js.es6 +15 -0
  55. data/app/assets/javascripts/angular/services/lib/spinner_state.js.es6 +45 -0
  56. data/app/assets/javascripts/angular/services/lib/tag_resource.js.es6 +14 -0
  57. data/app/assets/javascripts/angular/services/model/collection_dirty_awareness.js.es6 +33 -0
  58. data/app/assets/javascripts/angular/services/model/collection_model_base.js.es6 +75 -0
  59. data/app/assets/javascripts/angular/services/model/dirty_aware_collection_model.js.es6 +31 -0
  60. data/app/assets/javascripts/angular/services/model/dirty_aware_model.js.es6 +50 -0
  61. data/app/assets/javascripts/angular/services/model/model_base.js.es6 +80 -0
  62. data/app/assets/javascripts/angular/services/model/model_state.js.es6 +51 -0
  63. data/app/assets/javascripts/angular/services/model/models.js.es6 +15 -0
  64. data/app/assets/javascripts/angular/services/model/unpersisted_model.js.es6 +20 -0
  65. data/app/assets/javascripts/angular/services/model_generation/model_factory.js.es6 +28 -0
  66. data/app/assets/javascripts/angular/services/model_generation/model_generation.js.es6 +13 -0
  67. data/app/assets/javascripts/angular/services/model_generation/model_manager.js.es6 +86 -0
  68. data/app/assets/javascripts/angular/services/model_generation/resource_factory.js.es6 +38 -0
  69. data/app/assets/javascripts/angular/services/model_generation/standard_collection_model.js.es6 +25 -0
  70. data/app/assets/javascripts/angular/services/model_generation/standard_model.js.es6 +38 -0
  71. data/app/assets/javascripts/angular/services/query/query.js.es6 +55 -0
  72. data/app/assets/javascripts/angular/services/query/query_handler.js.es6 +40 -0
  73. data/app/assets/javascripts/angular/services/query/query_loader.js.es6 +54 -0
  74. data/app/assets/javascripts/angular/services/query/query_request_transformers.js.es6 +26 -0
  75. data/app/assets/javascripts/angular/services/query/query_resource.js.es6 +21 -0
  76. data/app/assets/javascripts/angular/services/query/query_tab.js.es6 +63 -0
  77. data/app/assets/javascripts/angular/services/query/query_versions.js.es6 +21 -0
  78. data/app/assets/javascripts/angular/services/result/result.js.es6 +26 -0
  79. data/app/assets/javascripts/angular/services/result/result_poller.js.es6 +30 -0
  80. data/app/assets/javascripts/angular/services/result/result_runner.js.es6 +48 -0
  81. data/app/assets/javascripts/angular/services/result/results.js.es6 +10 -0
  82. data/app/assets/javascripts/angular/services/schema/schema_column.js.es6 +93 -0
  83. data/app/assets/javascripts/angular/services/schema/schema_column_resource.js.es6 +12 -0
  84. data/app/assets/javascripts/angular/services/schema/schema_columns.js.es6 +57 -0
  85. data/app/assets/javascripts/angular/services/schema/schema_comment_resource.js.es6 +12 -0
  86. data/app/assets/javascripts/angular/services/services.js.es6 +140 -0
  87. data/app/assets/javascripts/angular/services/snippet/ace_snippet_manager.js.es6 +44 -0
  88. data/app/assets/javascripts/angular/services/visualization/source_renderer.js.es6 +70 -0
  89. data/app/assets/javascripts/angular/services/visualization/visualization.js.es6 +47 -0
  90. data/app/assets/javascripts/angular/services/visualization/visualization_service.js.es6 +67 -0
  91. data/app/assets/javascripts/angular/services/visualization/visualizations.js.es6 +11 -0
  92. data/app/assets/javascripts/application.js +22 -0
  93. data/app/assets/javascripts/lib/key_binding.js +24 -0
  94. data/app/assets/javascripts/lib/serialized_storage.js +11 -0
  95. data/app/assets/javascripts/lib/underscore_contrib/array_builders.js +190 -0
  96. data/app/assets/javascripts/lib/underscore_contrib/function_predicates.js +95 -0
  97. data/app/assets/javascripts/lib/underscore_contrib/object_builders.js +111 -0
  98. data/app/assets/javascripts/lib/underscore_contrib/object_selectors.js +112 -0
  99. data/app/assets/javascripts/lib/underscore_contrib/util_existential.js +15 -0
  100. data/app/assets/javascripts/lib/utils.js +29 -0
  101. data/app/assets/stylesheets/alert_bar.css.sass +13 -0
  102. data/app/assets/stylesheets/alerts.css.sass +66 -0
  103. data/app/assets/stylesheets/application.css.sass +35 -0
  104. data/app/assets/stylesheets/comments.css.sass +7 -0
  105. data/app/assets/stylesheets/index_components.css.sass +105 -0
  106. data/app/assets/stylesheets/queries.css.sass +110 -0
  107. data/app/assets/stylesheets/repl.css.sass +59 -0
  108. data/app/assets/stylesheets/results.css.sass +25 -0
  109. data/app/assets/stylesheets/schemas.css.sass +56 -0
  110. data/app/assets/stylesheets/sessions.css.sass +9 -0
  111. data/app/assets/stylesheets/shared.css.sass +157 -0
  112. data/app/assets/stylesheets/sidebar.css.sass +85 -0
  113. data/app/assets/stylesheets/snippets.css.sass +15 -0
  114. data/app/assets/stylesheets/sort_bar.css.sass +10 -0
  115. data/app/assets/stylesheets/spinners.css.sass +67 -0
  116. data/app/assets/stylesheets/summary.css.sass +16 -0
  117. data/app/assets/stylesheets/variables.css.sass +110 -0
  118. data/app/assets/stylesheets/visualizations.css.sass +15 -0
  119. data/app/controllers/alerts_controller.rb +72 -0
  120. data/app/controllers/application_controller.rb +38 -0
  121. data/app/controllers/columns_controller.rb +21 -0
  122. data/app/controllers/queries_controller.rb +85 -0
  123. data/app/controllers/query_versions_controller.rb +38 -0
  124. data/app/controllers/result_csvs_controller.rb +29 -0
  125. data/app/controllers/results_controller.rb +53 -0
  126. data/app/controllers/roles_controller.rb +9 -0
  127. data/app/controllers/schema_comments_controller.rb +47 -0
  128. data/app/controllers/snippets_controller.rb +67 -0
  129. data/app/controllers/tags_controller.rb +19 -0
  130. data/app/controllers/visualizations_controller.rb +61 -0
  131. data/app/mailers/alert_mailer.rb +8 -0
  132. data/app/models/ability.rb +31 -0
  133. data/app/models/alert.rb +139 -0
  134. data/app/models/alert_execution.rb +25 -0
  135. data/app/models/query.rb +85 -0
  136. data/app/models/query_execution.rb +39 -0
  137. data/app/models/query_role.rb +3 -0
  138. data/app/models/query_version.rb +61 -0
  139. data/app/models/result.rb +67 -0
  140. data/app/models/schema_comment.rb +3 -0
  141. data/app/models/snippet.rb +3 -0
  142. data/app/models/user.rb +19 -0
  143. data/app/models/visualization.rb +7 -0
  144. data/app/serializers/alert_serializer.rb +10 -0
  145. data/app/serializers/query_index_serializer.rb +7 -0
  146. data/app/serializers/query_serializer.rb +8 -0
  147. data/app/serializers/query_version_serializer.rb +3 -0
  148. data/app/serializers/result_serializer.rb +3 -0
  149. data/app/views/alert_mailer/alert_failing_email.html.haml +17 -0
  150. data/app/views/alerts/_index.html.haml +10 -0
  151. data/app/views/alerts/_index_item.html.haml +25 -0
  152. data/app/views/alerts/_index_sidebar.html.haml +20 -0
  153. data/app/views/alerts/_index_sort_bar.html.haml +22 -0
  154. data/app/views/alerts/_show.html.haml +90 -0
  155. data/app/views/application/_rollbar.html.erb +9 -0
  156. data/app/views/application/index.html.haml +1 -0
  157. data/app/views/application/unauthorized.html.haml +5 -0
  158. data/app/views/application/unauthorized.json +3 -0
  159. data/app/views/devise/sessions/new.html.haml +22 -0
  160. data/app/views/layouts/application.html.haml +78 -0
  161. data/app/views/queries/_alert.html.haml +6 -0
  162. data/app/views/queries/_comments.html.haml +5 -0
  163. data/app/views/queries/_index.html.haml +15 -0
  164. data/app/views/queries/_index_item.html.haml +37 -0
  165. data/app/views/queries/_index_sidebar.html.haml +58 -0
  166. data/app/views/queries/_index_sort_bar.html.haml +29 -0
  167. data/app/views/queries/_query_details.html.haml +81 -0
  168. data/app/views/queries/_query_version_sidebar.html.haml +46 -0
  169. data/app/views/queries/_repl.html.haml +79 -0
  170. data/app/views/queries/_results.html.haml +29 -0
  171. data/app/views/queries/_role_template.html.haml +3 -0
  172. data/app/views/queries/_show.html.haml +28 -0
  173. data/app/views/queries/_tag_template.html.haml +3 -0
  174. data/app/views/results/_show.html.haml +45 -0
  175. data/app/views/schemas/_index.html.haml +47 -0
  176. data/app/views/snippets/_index.html.haml +30 -0
  177. data/app/views/snippets/_index_item.html.haml +20 -0
  178. data/app/views/visualizations/_show.html.haml +83 -0
  179. data/bin/aleph +71 -0
  180. data/bin/bundle +3 -0
  181. data/bin/executables/bundle_runner.rb +12 -0
  182. data/bin/executables/clock.rb +7 -0
  183. data/bin/executables/deps.rb +10 -0
  184. data/bin/executables/import_env_variables.rb +17 -0
  185. data/bin/executables/init_db.rb +7 -0
  186. data/bin/executables/lib/config_generator.rb +51 -0
  187. data/bin/executables/lib/env_writer.rb +25 -0
  188. data/bin/executables/lib/import_env_file.rb +19 -0
  189. data/bin/executables/lib/seeder.rb +14 -0
  190. data/bin/executables/lib/utils.rb +30 -0
  191. data/bin/executables/playground.rb +130 -0
  192. data/bin/executables/seed_playground_db.rb +9 -0
  193. data/bin/executables/update_db.rb +7 -0
  194. data/bin/executables/web_server.rb +12 -0
  195. data/bin/executables/worker.rb +7 -0
  196. data/bin/rails +4 -0
  197. data/bin/rake +4 -0
  198. data/config/application.rb +59 -0
  199. data/config/attribute-map.yml +4 -0
  200. data/config/boot.rb +4 -0
  201. data/config/database.yml +40 -0
  202. data/config/environment.rb +5 -0
  203. data/config/environments/development.rb +37 -0
  204. data/config/environments/playground.rb +55 -0
  205. data/config/environments/production.rb +68 -0
  206. data/config/environments/staging.rb +75 -0
  207. data/config/environments/test.rb +46 -0
  208. data/config/initializers/01_internalize_configurations.rb +70 -0
  209. data/config/initializers/action_controller_renderers.rb +15 -0
  210. data/config/initializers/active_model_serializer.rb +7 -0
  211. data/config/initializers/assets.rb +8 -0
  212. data/config/initializers/backtrace_silencers.rb +7 -0
  213. data/config/initializers/cookies_serializer.rb +3 -0
  214. data/config/initializers/default_enviorment_variables.rb +8 -0
  215. data/config/initializers/devise.rb +297 -0
  216. data/config/initializers/filter_parameter_logging.rb +4 -0
  217. data/config/initializers/haml.rb +1 -0
  218. data/config/initializers/inflections.rb +16 -0
  219. data/config/initializers/mime_types.rb +4 -0
  220. data/config/initializers/net_http.rb +1 -0
  221. data/config/initializers/pester.rb +15 -0
  222. data/config/initializers/rails_admin.rb +27 -0
  223. data/config/initializers/redis.rb +14 -0
  224. data/config/initializers/rollbar.rb +45 -0
  225. data/config/initializers/session_store.rb +3 -0
  226. data/config/initializers/sql_logging_patch.rb +7 -0
  227. data/config/initializers/to_bool.rb +29 -0
  228. data/config/initializers/wrap_parameters.rb +14 -0
  229. data/config/locales/devise.en.yml +62 -0
  230. data/config/locales/en.yml +23 -0
  231. data/config/puma.rb +10 -0
  232. data/config/resque-pool.yml +15 -0
  233. data/config/resque.yml +10 -0
  234. data/config/routes.rb +33 -0
  235. data/config/secrets.yml +26 -0
  236. data/config.ru +4 -0
  237. data/db/migrate/20140710204753_database_begin.rb +150 -0
  238. data/lib/aleph_log_formatter.rb +5 -0
  239. data/lib/authentication.rb +17 -0
  240. data/lib/aws_s3.rb +7 -0
  241. data/lib/clock.rb +7 -0
  242. data/lib/compilable_parameter.rb +50 -0
  243. data/lib/count_publisher.rb +26 -0
  244. data/lib/csv_helper/aws.rb +30 -0
  245. data/lib/csv_helper/base.rb +20 -0
  246. data/lib/csv_helper/local.rb +18 -0
  247. data/lib/csv_serializer.rb +23 -0
  248. data/lib/csv_service.rb +12 -0
  249. data/lib/github/blob.rb +23 -0
  250. data/lib/github/commit.rb +37 -0
  251. data/lib/github/pusher.rb +94 -0
  252. data/lib/github/refs.rb +39 -0
  253. data/lib/github/tree.rb +29 -0
  254. data/lib/github.rb +64 -0
  255. data/lib/interaction/query_creation.rb +27 -0
  256. data/lib/interaction/query_interaction.rb +35 -0
  257. data/lib/interaction/query_update.rb +62 -0
  258. data/lib/interaction/result_creation.rb +48 -0
  259. data/lib/pagination_search/attribute_set.rb +61 -0
  260. data/lib/pagination_search/base_relation.rb +80 -0
  261. data/lib/pagination_search/hash_paginate.rb +74 -0
  262. data/lib/pagination_search/paginated_records.rb +16 -0
  263. data/lib/pagination_search/pagination.rb +12 -0
  264. data/lib/pagination_search/search_conditions.rb +59 -0
  265. data/lib/query_version_support.rb +14 -0
  266. data/lib/redis_result_row_count.rb +26 -0
  267. data/lib/redshift_connection_pool.rb +8 -0
  268. data/lib/redshift_pg/connection.rb +44 -0
  269. data/lib/redshift_pg/redshift_pg.rb +15 -0
  270. data/lib/result_csv_generator.rb +40 -0
  271. data/lib/role.rb +40 -0
  272. data/lib/sample_skimmer.rb +30 -0
  273. data/lib/schema_comment_matcher.rb +27 -0
  274. data/lib/schemas/descriptor.rb +85 -0
  275. data/lib/schemas/descriptors.rb +10 -0
  276. data/lib/schemas/paginate.rb +21 -0
  277. data/lib/schemas/redis_store.rb +22 -0
  278. data/lib/simple_cache.rb +13 -0
  279. data/lib/sql_compiler.rb +33 -0
  280. data/lib/summarizer.rb +18 -0
  281. data/lib/tasks/karma.rake +32 -0
  282. data/lib/tasks/resque_setup.rake +18 -0
  283. data/playground_data/1.csv +13 -0
  284. data/playground_data/aleph.playground.sqlite3 +0 -0
  285. data/public/404.html +26 -0
  286. data/public/422.html +26 -0
  287. data/public/500.html +25 -0
  288. data/public/aleph.png +0 -0
  289. data/public/assets/.sprockets-manifest-24b5998edb20c5b4d6edf39d44cd3ff7.json +1 -0
  290. data/public/assets/FontAwesome-9ccfa32dd4cd1b8e83f68899d85bd5e6.otf +0 -0
  291. data/public/assets/ZeroClipboard-8b5c117b88fe37e32fd34a70fdf60026.swf +0 -0
  292. data/public/assets/angular/aleph.js-19b4df67407de5dab249abfc391c0eaf.es6 +90 -0
  293. data/public/assets/angular/config/schema_completer_config.js-1b696920b5e04f75620630d75117b201.es6 +71 -0
  294. data/public/assets/angular/controllers/alerts/alert_index_controller.js-4344581b1e9b456c3f991f96bb4d403d.es6 +16 -0
  295. data/public/assets/angular/controllers/alerts/alert_show_controller.js-a984dc82fbcac380cdc8682bf8986933.es6 +99 -0
  296. data/public/assets/angular/controllers/controllers.js-7431ae468ea2f0d392661448a61cfdf3.es6 +65 -0
  297. data/public/assets/angular/controllers/query/query_index_controller.js-828eadeee6a971b11b5c07f65f0c6def.es6 +80 -0
  298. data/public/assets/angular/controllers/query/query_repl_controller.js-3c4bac22e41766e2e83e720d53acade3.es6 +147 -0
  299. data/public/assets/angular/controllers/query/query_show_controller.js-020c83fd94ece7d55bd94b9981a40083.es6 +43 -0
  300. data/public/assets/angular/controllers/schema/schema_index_controller.js-d0d790d168b49caefa4b8f7993c928f1.es6 +61 -0
  301. data/public/assets/angular/controllers/snippet/snippet_index_controller.js-9191ee2e37d16d5807b8a7f45530a6c2.es6 +80 -0
  302. data/public/assets/angular/directives/directives.js-44fda752585bddc5d026feaab8b14108.es6 +30 -0
  303. data/public/assets/angular/directives/query/query_details_directive.js-2dd979e2463826558f166d9dc9e2c8a9.es6 +87 -0
  304. data/public/assets/angular/directives/query/query_version_sidebar_directive.js-b19ba8a9bf4e66c5740e9b9f9495cee1.es6 +65 -0
  305. data/public/assets/angular/directives/result/result_directive.js-76c151e9277e35578f92b076c2fa5b06.es6 +59 -0
  306. data/public/assets/angular/directives/result/results_directive.js-fcbf9750790823a11ca313e630bd2b0f.es6 +30 -0
  307. data/public/assets/angular/directives/visualization_directive.js-82cb45a52eba62deb283a3699add1b33.es6 +101 -0
  308. data/public/assets/angular/filters/filters.js-48cdb16fc89337e861c9f18ad57fd9bf.es6 +27 -0
  309. data/public/assets/angular/services/alert/alert.js-a76ea96e948de324fcc00f3ef3ecae4e.es6 +51 -0
  310. data/public/assets/angular/services/alert/alert_resource.js-ac68ea99936eb213c0fb37d4fbb1511a.es6 +10 -0
  311. data/public/assets/angular/services/lib/ace_completers.js-5353182bc538210dad12865ad6a060fd.es6 +29 -0
  312. data/public/assets/angular/services/lib/ace_sql_parse.js-4114a8ad4fe4dbf4f72c0ab7fca22e83.es6 +156 -0
  313. data/public/assets/angular/services/lib/action_handler.js-85a8f75f507efcf2fe950fa7717b6976.es6 +73 -0
  314. data/public/assets/angular/services/lib/alert_flash.js-7a4fe7ef5510a224677a12ecf2fe973b.es6 +30 -0
  315. data/public/assets/angular/services/lib/default_ace_configurator_service.js-9b83d6b53495dafe10bfed5074c3ec01.es6 +74 -0
  316. data/public/assets/angular/services/lib/github_url_service.js-719084a625f60d20c24097f00813b481.es6 +53 -0
  317. data/public/assets/angular/services/lib/keyword_completer.js-560b51694457619401c72431dd7b647e.es6 +36 -0
  318. data/public/assets/angular/services/lib/local_resource.js-9b57357ed203c783708e48154721242a.es6 +20 -0
  319. data/public/assets/angular/services/lib/lock_service.js-32eb33fda9c27fb5643b25c63099b52c.es6 +48 -0
  320. data/public/assets/angular/services/lib/locking_poll_service.js-d0271cc07d20ec73291e7175e1714d42.es6 +42 -0
  321. data/public/assets/angular/services/lib/matcher_runner.js-bd63f4c6ad965716c5b793d3c4602563.es6 +65 -0
  322. data/public/assets/angular/services/lib/navigation_guard.js-5c7497900f99319f3ef76b83662c20cd.es6 +45 -0
  323. data/public/assets/angular/services/lib/open_repl_service.js-2332490470ea58f3e5ce7f6fe5dd2659.es6 +56 -0
  324. data/public/assets/angular/services/lib/page_title_manager.js-227f9ddb49d23bfa934bf216ef96ccbd.es6 +38 -0
  325. data/public/assets/angular/services/lib/pagination.js-baa9a496d01b87f90c588c51864d1533.es6 +114 -0
  326. data/public/assets/angular/services/lib/pagination_components.js-4fcc03120d1299713347b487f1e8fd44.es6 +91 -0
  327. data/public/assets/angular/services/lib/parameter_methods.js-16ecb25ffb24d5870dfc17f9f408fa5b.es6 +35 -0
  328. data/public/assets/angular/services/lib/role_model.js-3d5072f279676294e7d17cbb4bb3adb5.es6 +21 -0
  329. data/public/assets/angular/services/lib/schema_completer.js-d04d49642967fd9f8e2c95e0df81f2ae.es6 +56 -0
  330. data/public/assets/angular/services/lib/selection_tag_input.js-86cc6d564c108d722951b6fcd2b51221.es6 +42 -0
  331. data/public/assets/angular/services/lib/server_configurations.js-fd8c16a3d02926e7597240566808c141.es6 +15 -0
  332. data/public/assets/angular/services/lib/spinner_state.js-315bb62df18f9370a89f8b865eb1766a.es6 +45 -0
  333. data/public/assets/angular/services/lib/tag_resource.js-8849bbdd579bd38b36a362bed926c2f2.es6 +14 -0
  334. data/public/assets/angular/services/model/collection_dirty_awareness.js-8a78450bd8b565fb03633ab735893508.es6 +33 -0
  335. data/public/assets/angular/services/model/collection_model_base.js-8092335acde425d28718c1a9fc677d39.es6 +75 -0
  336. data/public/assets/angular/services/model/dirty_aware_collection_model.js-6f4d2b409a033f5ffc6bd5a747df2046.es6 +31 -0
  337. data/public/assets/angular/services/model/dirty_aware_model.js-ec1a086f3ec459827dbd5381bd970975.es6 +50 -0
  338. data/public/assets/angular/services/model/model_base.js-9fd807dfdf4f26afe60d8e282ca08e6c.es6 +80 -0
  339. data/public/assets/angular/services/model/model_state.js-3e96e381ea7a9eff857081ffbf3a8bab.es6 +51 -0
  340. data/public/assets/angular/services/model/models.js-6798762a6e263be75c7c4e9f8a19da66.es6 +15 -0
  341. data/public/assets/angular/services/model/unpersisted_model.js-49597959c989e68c713fd826743bb7b5.es6 +20 -0
  342. data/public/assets/angular/services/model_generation/model_factory.js-0bccc6a2e9b4738c67230fc68d9780ae.es6 +28 -0
  343. data/public/assets/angular/services/model_generation/model_generation.js-f08c6eff199b5ad02b2e2bdf866d69ff.es6 +13 -0
  344. data/public/assets/angular/services/model_generation/model_manager.js-b05d8f00bc4499c50098ae31013de88c.es6 +86 -0
  345. data/public/assets/angular/services/model_generation/resource_factory.js-e8ce2f4be9383d885dbb965c8e425bab.es6 +38 -0
  346. data/public/assets/angular/services/model_generation/standard_collection_model.js-19c44dc3a937a85d825c5a2f020a6769.es6 +25 -0
  347. data/public/assets/angular/services/model_generation/standard_model.js-74439b041eebfc7e0fad454cf6e32192.es6 +38 -0
  348. data/public/assets/angular/services/query/query.js-7b6228d0a5c1a6ea76242f4aa49aafd0.es6 +55 -0
  349. data/public/assets/angular/services/query/query_handler.js-d8cb3c66bcf6d16cd13bb5bcd0921496.es6 +40 -0
  350. data/public/assets/angular/services/query/query_loader.js-1fbc8b859778d46b73b9adc300984851.es6 +54 -0
  351. data/public/assets/angular/services/query/query_request_transformers.js-522901477c7848324cd5c014005a85c8.es6 +26 -0
  352. data/public/assets/angular/services/query/query_resource.js-b809fbfd1c379619fa07ef8e52509810.es6 +21 -0
  353. data/public/assets/angular/services/query/query_tab.js-fe34f5e6d0c813d2d92838be14cd6783.es6 +63 -0
  354. data/public/assets/angular/services/query/query_versions.js-aa3aec9021354a7394797101ea500887.es6 +21 -0
  355. data/public/assets/angular/services/result/result.js-be8178c80c767a651a97537b2b0149d5.es6 +26 -0
  356. data/public/assets/angular/services/result/result_poller.js-b15617d53f164cbe5636bb5573a70504.es6 +30 -0
  357. data/public/assets/angular/services/result/result_runner.js-ce2c5b3121c8e67903c302e600749c14.es6 +48 -0
  358. data/public/assets/angular/services/result/results.js-53088d6088f6b4783b274a64322d361c.es6 +10 -0
  359. data/public/assets/angular/services/schema/schema_column.js-3908faecc9874fa08484d7490701a7d4.es6 +93 -0
  360. data/public/assets/angular/services/schema/schema_column_resource.js-a6982ce9698b104192c4e455300df455.es6 +12 -0
  361. data/public/assets/angular/services/schema/schema_columns.js-c63a16e2e0778a885bd27c7cf2ed7d88.es6 +57 -0
  362. data/public/assets/angular/services/schema/schema_comment_resource.js-20254ea1a4e7b4850c9f21f9619130ce.es6 +12 -0
  363. data/public/assets/angular/services/services.js-6225c5ea24a9082506d1932d7884b53b.es6 +140 -0
  364. data/public/assets/angular/services/snippet/ace_snippet_manager.js-dbbba5d8ad5040042b469b294c4d7228.es6 +44 -0
  365. data/public/assets/angular/services/visualization/source_renderer.js-d7274c88b067a35f2e91bf7f39be7d47.es6 +70 -0
  366. data/public/assets/angular/services/visualization/visualization.js-23e36c87721aa263dd3f99769027cabb.es6 +47 -0
  367. data/public/assets/angular/services/visualization/visualization_service.js-25de86b5ceef60cf2b1dfde5fb0e9216.es6 +67 -0
  368. data/public/assets/angular/services/visualization/visualizations.js-1227bc3dcd67e85c8050d82360a26d53.es6 +11 -0
  369. data/public/assets/application-9153e0bf570016651e5eb8c67e037d3a.css +10 -0
  370. data/public/assets/application-ef5c2ae95804ac9785f190a9aea7ad8b.js +149 -0
  371. data/public/assets/bootstrap/glyphicons-halflings-regular-448c34a56d699c29117adc64c43affeb.woff2 +0 -0
  372. data/public/assets/bootstrap/glyphicons-halflings-regular-89889688147bd7575d6327160d64e760.svg +288 -0
  373. data/public/assets/bootstrap/glyphicons-halflings-regular-e18bbf611f2a2e43afc071aa2f4e1512.ttf +0 -0
  374. data/public/assets/bootstrap/glyphicons-halflings-regular-f4769f9bdb7466be65088239c12046d1.eot +0 -0
  375. data/public/assets/bootstrap/glyphicons-halflings-regular-fa2772327f55d8198301fdb8bcfc8158.woff +0 -0
  376. data/public/assets/fontawesome-webfont-4f0022f25672c7f501c339cbf98d9117.ttf +0 -0
  377. data/public/assets/fontawesome-webfont-776d58f453c8fe5d6a89e9c31ee223ff.svg +504 -0
  378. data/public/assets/fontawesome-webfont-90186830c9c50a0fed932494581761d9.eot +0 -0
  379. data/public/assets/fontawesome-webfont-926c93d201fe51c8f351e858468980c3.woff2 +0 -0
  380. data/public/assets/fontawesome-webfont-fdf491ce5ff5b2da02708cd0e9864719.woff +0 -0
  381. data/public/assets/glyphicons-halflings-regular-0a5c48c69a25a93e37ed62db813387fa.svg +229 -0
  382. data/public/assets/glyphicons-halflings-regular-47da44498fc073d9fff9ab0cdb0bef8e.ttf +0 -0
  383. data/public/assets/glyphicons-halflings-regular-5eae1f7217b606d3580dd70ac840fea1.woff +0 -0
  384. data/public/assets/glyphicons-halflings-regular-aa16cd35628e6dddf56e766c9aa4ae63.eot +0 -0
  385. data/public/assets/jquery-ui/ui-bg_flat_0_aaaaaa_40x100-2a44fbdb7360c60122bcf6dcef0387d8.png +0 -0
  386. data/public/assets/jquery-ui/ui-bg_flat_75_ffffff_40x100-8692e6efddf882acbff144c38ea7dfdf.png +0 -0
  387. data/public/assets/jquery-ui/ui-bg_glass_55_fbf9ee_1x400-f8f4558e0b92ff2cd6136781533902ec.png +0 -0
  388. data/public/assets/jquery-ui/ui-bg_glass_65_ffffff_1x400-e5a8f32e28fd5c27bf0fed33c8a8b9b5.png +0 -0
  389. data/public/assets/jquery-ui/ui-bg_glass_75_dadada_1x400-c12c6510dad3ebfa64c8a30e959a2469.png +0 -0
  390. data/public/assets/jquery-ui/ui-bg_glass_75_e6e6e6_1x400-f4254356c2a8c9a383205ef2c4de22c4.png +0 -0
  391. data/public/assets/jquery-ui/ui-bg_glass_95_fef1ec_1x400-5a3be2d8fff8324d59aec3df7b0a0c83.png +0 -0
  392. data/public/assets/jquery-ui/ui-bg_highlight-soft_75_cccccc_1x100-72c593d16e998952cd8d798fee33c6f3.png +0 -0
  393. data/public/assets/jquery-ui/ui-icons_222222_256x240-9129e086dc488d8bcaf808510bc646ba.png +0 -0
  394. data/public/assets/jquery-ui/ui-icons_2e83ff_256x240-25162bf857a8eb83ea932a58436e1049.png +0 -0
  395. data/public/assets/jquery-ui/ui-icons_454545_256x240-771099482bdc1571ece41073b1752596.png +0 -0
  396. data/public/assets/jquery-ui/ui-icons_888888_256x240-faf6f5dc44e713178784c1fb053990aa.png +0 -0
  397. data/public/assets/jquery-ui/ui-icons_cd0a0a_256x240-5d8808d43cefca6f6781a5316d176632.png +0 -0
  398. data/public/assets/octicons-0a82c1edade24862533bbe96ebeaea47.eot +0 -0
  399. data/public/assets/octicons-103abd6cc0199e2519ef6f1aac4bb0e0.ttf +0 -0
  400. data/public/assets/octicons-adc17600a2b7a648eba306c2e1426b85.svg +183 -0
  401. data/public/assets/octicons-be82065223a03ba577de159d97a5d63d.woff +0 -0
  402. data/public/assets/octicons-local-72e4167c13648cb89e9e96cdd212cb82.ttf +0 -0
  403. data/public/assets/rails_admin/aristo/images/bg_fallback-a7547e71656b1e538b93ddb49dfc98d3.png +0 -0
  404. data/public/assets/rails_admin/aristo/images/icon_sprite-415c1eec8a2d31d217d4d1d5a1d44345.png +0 -0
  405. data/public/assets/rails_admin/aristo/images/progress_bar-449b2fab5cf4122c17a416f6e26569fe.gif +0 -0
  406. data/public/assets/rails_admin/aristo/images/slider_handles-ba57b6efb64ca6263f77ce2624ad71ee.png +0 -0
  407. data/public/assets/rails_admin/aristo/images/ui-icons_222222_256x240-a2c05c5e967f9cf4dae51c1243b3b93c.png +0 -0
  408. data/public/assets/rails_admin/aristo/images/ui-icons_454545_256x240-a7a7eff72c4f562524dc472824aab656.png +0 -0
  409. data/public/assets/rails_admin/base/README-f7dd742c2237cb1959438b94c7503a41.txt +2 -0
  410. data/public/assets/rails_admin/bootstrap/glyphicons-halflings-d4fef5262f29f592560fb59918a1c052.png +0 -0
  411. data/public/assets/rails_admin/bootstrap/glyphicons-halflings-white-9bbc6e9602998a385c2ea13df56470fd.png +0 -0
  412. data/public/assets/rails_admin/bullet_black-06d345566cf9e0f97a23bb07ab3d50d9.png +0 -0
  413. data/public/assets/rails_admin/bullet_white-469b537fa21b7143f719578f7426825d.png +0 -0
  414. data/public/assets/rails_admin/calendar-697f5a44753da70028cfd04b98ac45d2.png +0 -0
  415. data/public/assets/rails_admin/clock-0cc82b549af3df4f730a02335f54b0df.png +0 -0
  416. data/public/assets/rails_admin/colorpicker/colorpicker_background-7aaa2a726200c0ac3ba43c01f073a93d.png +0 -0
  417. data/public/assets/rails_admin/colorpicker/colorpicker_hex-cbc06f4015cbb276a3dd966e1be37c25.png +0 -0
  418. data/public/assets/rails_admin/colorpicker/colorpicker_hsb_b-2315aba3c2fbbcfcc22869b21836c31d.png +0 -0
  419. data/public/assets/rails_admin/colorpicker/colorpicker_hsb_h-3120023551e3601467cf52e1c8aaae9e.png +0 -0
  420. data/public/assets/rails_admin/colorpicker/colorpicker_hsb_s-77a77892bdef0906fdfc3426d06108fd.png +0 -0
  421. data/public/assets/rails_admin/colorpicker/colorpicker_indic-f485d07540a89502e36dc1a55cec05d0.gif +0 -0
  422. data/public/assets/rails_admin/colorpicker/colorpicker_overlay-4b2dd6f78c4aac5cc932e845698b2db5.png +0 -0
  423. data/public/assets/rails_admin/colorpicker/colorpicker_rgb_b-2315aba3c2fbbcfcc22869b21836c31d.png +0 -0
  424. data/public/assets/rails_admin/colorpicker/colorpicker_rgb_g-475afe3f4f69e59ff30a445384a8d961.png +0 -0
  425. data/public/assets/rails_admin/colorpicker/colorpicker_rgb_r-02de28945293fe2fd026c9be3b89955a.png +0 -0
  426. data/public/assets/rails_admin/colorpicker/colorpicker_select-cdf55197d05f18c552dc35bdb858fa2a.gif +0 -0
  427. data/public/assets/rails_admin/colorpicker/colorpicker_submit-9912e5cf348e0be359ff9b1078fbb7da.png +0 -0
  428. data/public/assets/rails_admin/colorpicker/custom_background-a0ab8ff3e2b85b1f8ed5a4d86967471b.png +0 -0
  429. data/public/assets/rails_admin/colorpicker/custom_hex-065e780d7b89f7dda63a472caa7c2bdd.png +0 -0
  430. data/public/assets/rails_admin/colorpicker/custom_hsb_b-66f5963cf1a0a2680acbcac2bb77f40d.png +0 -0
  431. data/public/assets/rails_admin/colorpicker/custom_hsb_h-cd1f2e27122aeca17af416f328b758cd.png +0 -0
  432. data/public/assets/rails_admin/colorpicker/custom_hsb_s-ca6f3e4f0c1fc2cb110c788018369e07.png +0 -0
  433. data/public/assets/rails_admin/colorpicker/custom_indic-04660eb352eb259581a36a0fe8da2d4d.gif +0 -0
  434. data/public/assets/rails_admin/colorpicker/custom_rgb_b-64bc0c5110f84efe32e82c58d50660f6.png +0 -0
  435. data/public/assets/rails_admin/colorpicker/custom_rgb_g-33fe011475956750a457b1f93f1b9075.png +0 -0
  436. data/public/assets/rails_admin/colorpicker/custom_rgb_r-18f2ee37089d850c52b212d8a31aac92.png +0 -0
  437. data/public/assets/rails_admin/colorpicker/custom_submit-9d0a14eebb9ae04edfb8099827a42968.png +0 -0
  438. data/public/assets/rails_admin/colorpicker/select-76bd5c10f34de24b73ff4454735d3e18.png +0 -0
  439. data/public/assets/rails_admin/colorpicker/select2-d3fea9a451ac2c29bcd4a82b6e4f326a.png +0 -0
  440. data/public/assets/rails_admin/colorpicker/slider-db040ce7280fc74269e330a862e738e6.png +0 -0
  441. data/public/assets/rails_admin/jquery.colorpicker-7c36c2fac54a031f6e0dfe6ad137cfb1.js +1 -0
  442. data/public/assets/rails_admin/jquery.colorpicker-e402a30af31a4ba5957fec816dc9239c.css +1 -0
  443. data/public/assets/rails_admin/logo-9b479a57b493ee824767163101a5409f.png +0 -0
  444. data/public/assets/rails_admin/magnifier-4fcdfd820ff2e951458af3d1309ab20c.png +0 -0
  445. data/public/assets/rails_admin/multiselect/icon_sprite-415c1eec8a2d31d217d4d1d5a1d44345.png +0 -0
  446. data/public/assets/rails_admin/multiselect/ui-icon-circle-triangle-n-dark-32c1cfdd900379bf62658e475fb2ba38.png +0 -0
  447. data/public/assets/rails_admin/multiselect/ui-icon-circle-triangle-n-light-73160d919a189ba13bd4387e3623b7e9.png +0 -0
  448. data/public/assets/rails_admin/multiselect/ui-icon-circle-triangle-s-dark-c15e6bff59c80c5473236cf77870f31d.png +0 -0
  449. data/public/assets/rails_admin/multiselect/ui-icon-circle-triangle-s-light-fbf43811420f67d49d4dc64c7817f72c.png +0 -0
  450. data/public/assets/rails_admin/rails_admin-d25a684b9f690652469ceb212fbe7b95.js +328 -0
  451. data/public/assets/rails_admin/rails_admin-d85fb3c8bbff377491ed5af5239cf185.css +8 -0
  452. data/public/assets/resque_web/application-b29b34115c3ad5c539f26114fc91e584.css +4 -0
  453. data/public/assets/resque_web/application-d2bc6e68cf7c6215e804fe9e3f46f1d0.js +111 -0
  454. data/public/assets/resque_web/idle-53474088772d9917bd463b19efa32fc3.png +0 -0
  455. data/public/assets/resque_web/lifebuoy-0281230b31ba4078685f4df3e8169534.png +0 -0
  456. data/public/assets/resque_web/poll-af53f85832c41a9cde68b08cb09711f1.png +0 -0
  457. data/public/assets/resque_web/rails-9c0a079bdd7701d7e729bd956823d153.png +0 -0
  458. data/public/assets/resque_web/working-26a36c5119cbdcc64ebade2c5f8c389d.png +0 -0
  459. data/public/assets/twitter/bootstrap/glyphicons-halflings-2516339970d710819585f90773aebe0a.png +0 -0
  460. data/public/assets/twitter/bootstrap/glyphicons-halflings-white-9bbc6e9602998a385c2ea13df56470fd.png +0 -0
  461. data/public/bg_big.svg +2 -0
  462. data/public/bg_new.svg +2 -0
  463. data/public/favicon.ico +0 -0
  464. data/public/resources/keyword_config.json +51 -0
  465. data/public/resources/visualization/area.html +17 -0
  466. data/public/resources/visualization/area_step.html +17 -0
  467. data/public/resources/visualization/bar.html +17 -0
  468. data/public/resources/visualization/custom.html +6 -0
  469. data/public/resources/visualization/line.html +16 -0
  470. data/public/resources/visualization/presets.json +13 -0
  471. data/public/resources/visualization/scatter.html +17 -0
  472. data/public/resources/visualization/spline.html +17 -0
  473. data/public/resources/visualization/spline_area.html +17 -0
  474. data/public/resources/visualization/stacked_area.html +18 -0
  475. data/public/resources/visualization/stacked_bar.html +18 -0
  476. data/public/resources/visualization/stacked_spline_area.html +18 -0
  477. data/public/resources/visualization/template.json +12 -0
  478. data/public/robots.txt +2 -0
  479. data/vendor/assets/javascripts/ace/ace.js +18655 -0
  480. data/vendor/assets/javascripts/ace/ext-language_tools.js +1937 -0
  481. data/vendor/assets/javascripts/ace/mode-html.js +2794 -0
  482. data/vendor/assets/javascripts/ace/mode-pgsql.js +1503 -0
  483. data/vendor/assets/javascripts/ace/snippets/coffee.js +102 -0
  484. data/vendor/assets/javascripts/ace/snippets/css.js +974 -0
  485. data/vendor/assets/javascripts/ace/snippets/haml.js +27 -0
  486. data/vendor/assets/javascripts/ace/snippets/html.js +835 -0
  487. data/vendor/assets/javascripts/ace/snippets/html_elixir.js +7 -0
  488. data/vendor/assets/javascripts/ace/snippets/html_ruby.js +7 -0
  489. data/vendor/assets/javascripts/ace/snippets/javascript.js +202 -0
  490. data/vendor/assets/javascripts/ace/snippets/json.js +7 -0
  491. data/vendor/assets/javascripts/ace/snippets/jsp.js +106 -0
  492. data/vendor/assets/javascripts/ace/snippets/jsx.js +7 -0
  493. data/vendor/assets/javascripts/ace/snippets/less.js +7 -0
  494. data/vendor/assets/javascripts/ace/snippets/mysql.js +7 -0
  495. data/vendor/assets/javascripts/ace/snippets/pgsql.js +7 -0
  496. data/vendor/assets/javascripts/ace/snippets/plain_text.js +7 -0
  497. data/vendor/assets/javascripts/ace/snippets/rhtml.js +7 -0
  498. data/vendor/assets/javascripts/ace/snippets/sass.js +7 -0
  499. data/vendor/assets/javascripts/ace/snippets/scss.js +7 -0
  500. data/vendor/assets/javascripts/ace/snippets/snippets.js +16 -0
  501. data/vendor/assets/javascripts/ace/snippets/sql.js +33 -0
  502. data/vendor/assets/javascripts/ace/snippets/sqlserver.js +76 -0
  503. data/vendor/assets/javascripts/ace/snippets/svg.js +7 -0
  504. data/vendor/assets/javascripts/ace/snippets/text.js +7 -0
  505. data/vendor/assets/javascripts/ace/snippets/textile.js +37 -0
  506. data/vendor/assets/javascripts/ace/theme-monokai.js +105 -0
  507. data/vendor/assets/javascripts/angular-filter/angular-filter.js +2271 -0
  508. data/vendor/assets/javascripts/angular-hotkeys/hotkeys.js +1523 -0
  509. data/vendor/assets/javascripts/angular-selection-model/selection-model.js +563 -0
  510. data/vendor/assets/javascripts/angular-spinner/treasure-overlay-spinner.js +53 -0
  511. data/vendor/assets/javascripts/angular-ui-ace/ui-ace.js +298 -0
  512. data/vendor/assets/javascripts/angular-ui-bootstrap/ui-bootstrap-tpls-0.14.3.js +8503 -0
  513. data/vendor/assets/javascripts/d3/c3.min.js +5 -0
  514. data/vendor/assets/javascripts/d3/d3.v3.min.js +5 -0
  515. data/vendor/assets/javascripts/infinite-scroll/infinite-scroll.js +186 -0
  516. data/vendor/assets/javascripts/ng-clip/ngClip.js +84 -0
  517. data/vendor/assets/javascripts/ng-tags-input/ng-tags-input.min.js +1 -0
  518. data/vendor/assets/javascripts/pluralize/pluralize.js +453 -0
  519. data/vendor/assets/javascripts/underscore-js/underscore.js +1548 -0
  520. data/vendor/assets/stylesheets/angular-hotkeys/hotkeys.css +110 -0
  521. data/vendor/assets/stylesheets/angular-spinner/treasure-overlay-spinner.css +136 -0
  522. data/vendor/assets/stylesheets/c3/c3.min.css +1 -0
  523. data/vendor/assets/stylesheets/ng-tags-input/ng-tags-input.bootstrap.min.css +1 -0
  524. data/vendor/assets/stylesheets/ng-tags-input/ng-tags-input.min.css +1 -0
  525. data/vendor/assets/stylesheets/octicons/README.md +1 -0
  526. data/vendor/assets/stylesheets/octicons/sprockets-octicons.scss +217 -0
  527. metadata +600 -0
@@ -0,0 +1,2271 @@
1
+ /**
2
+ * Bunch of useful filters for angularJS(with no external dependencies!)
3
+ * @version v0.5.5 - 2015-08-07 * @link https://github.com/a8m/angular-filter
4
+ * @author Ariel Mashraki <ariel@mashraki.co.il>
5
+ * @license MIT License, http://www.opensource.org/licenses/MIT
6
+ */
7
+ (function ( window, angular, undefined ) {
8
+ /*jshint globalstrict:true*/
9
+ 'use strict';
10
+
11
+ var isDefined = angular.isDefined,
12
+ isUndefined = angular.isUndefined,
13
+ isFunction = angular.isFunction,
14
+ isString = angular.isString,
15
+ isNumber = angular.isNumber,
16
+ isObject = angular.isObject,
17
+ isArray = angular.isArray,
18
+ forEach = angular.forEach,
19
+ extend = angular.extend,
20
+ copy = angular.copy,
21
+ equals = angular.equals;
22
+
23
+
24
+ /**
25
+ * @description
26
+ * get an object and return array of values
27
+ * @param object
28
+ * @returns {Array}
29
+ */
30
+ function toArray(object) {
31
+ return isArray(object)
32
+ ? object
33
+ : Object.keys(object).map(function(key) {
34
+ return object[key];
35
+ });
36
+ }
37
+
38
+ /**
39
+ * @param value
40
+ * @returns {boolean}
41
+ */
42
+ function isNull(value) {
43
+ return value === null;
44
+ }
45
+
46
+ /**
47
+ * @description
48
+ * return if object contains partial object
49
+ * @param partial{object}
50
+ * @param object{object}
51
+ * @returns {boolean}
52
+ */
53
+ function objectContains(partial, object) {
54
+ var keys = Object.keys(partial);
55
+
56
+ return keys.map(function(el) {
57
+ return (object[el] !== undefined) && (object[el] == partial[el]);
58
+ }).indexOf(false) == -1;
59
+
60
+ }
61
+
62
+ /**
63
+ * @description
64
+ * search for approximate pattern in string
65
+ * @param word
66
+ * @param pattern
67
+ * @returns {*}
68
+ */
69
+ function hasApproxPattern(word, pattern) {
70
+ if(pattern === '')
71
+ return word;
72
+
73
+ var index = word.indexOf(pattern.charAt(0));
74
+
75
+ if(index === -1)
76
+ return false;
77
+
78
+ return hasApproxPattern(word.substr(index+1), pattern.substr(1))
79
+ }
80
+
81
+ /**
82
+ * @description
83
+ * return the first n element of an array,
84
+ * if expression provided, is returns as long the expression return truthy
85
+ * @param array
86
+ * @param n {number}
87
+ * @param expression {$parse}
88
+ * @return array or single object
89
+ */
90
+ function getFirstMatches(array, n, expression) {
91
+ var count = 0;
92
+
93
+ return array.filter(function(elm) {
94
+ var rest = isDefined(expression) ? (count < n && expression(elm)) : count < n;
95
+ count = rest ? count+1 : count;
96
+
97
+ return rest;
98
+ });
99
+ }
100
+ /**
101
+ * Polyfill to ECMA6 String.prototype.contains
102
+ */
103
+ if (!String.prototype.contains) {
104
+ String.prototype.contains = function() {
105
+ return String.prototype.indexOf.apply(this, arguments) !== -1;
106
+ };
107
+ }
108
+
109
+ /**
110
+ * @param num {Number}
111
+ * @param decimal {Number}
112
+ * @param $math
113
+ * @returns {Number}
114
+ */
115
+ function convertToDecimal(num, decimal, $math){
116
+ return $math.round(num * $math.pow(10,decimal)) / ($math.pow(10,decimal));
117
+ }
118
+
119
+ /**
120
+ * @description
121
+ * Get an object, and return an array composed of it's properties names(nested too).
122
+ * @param obj {Object}
123
+ * @param stack {Array}
124
+ * @param parent {String}
125
+ * @returns {Array}
126
+ * @example
127
+ * parseKeys({ a:1, b: { c:2, d: { e: 3 } } }) ==> ["a", "b.c", "b.d.e"]
128
+ */
129
+ function deepKeys(obj, stack, parent) {
130
+ stack = stack || [];
131
+ var keys = Object.keys(obj);
132
+
133
+ keys.forEach(function(el) {
134
+ //if it's a nested object
135
+ if(isObject(obj[el]) && !isArray(obj[el])) {
136
+ //concatenate the new parent if exist
137
+ var p = parent ? parent + '.' + el : parent;
138
+ deepKeys(obj[el], stack, p || el);
139
+ } else {
140
+ //create and save the key
141
+ var key = parent ? parent + '.' + el : el;
142
+ stack.push(key)
143
+ }
144
+ });
145
+ return stack
146
+ }
147
+
148
+ /**
149
+ * @description
150
+ * Test if given object is a Scope instance
151
+ * @param obj
152
+ * @returns {Boolean}
153
+ */
154
+ function isScope(obj) {
155
+ return obj && obj.$evalAsync && obj.$watch;
156
+ }
157
+
158
+ /**
159
+ * @ngdoc filter
160
+ * @name a8m.angular
161
+ * @kind function
162
+ *
163
+ * @description
164
+ * reference to angular function
165
+ */
166
+
167
+ angular.module('a8m.angular', [])
168
+
169
+ .filter('isUndefined', function () {
170
+ return function (input) {
171
+ return angular.isUndefined(input);
172
+ }
173
+ })
174
+ .filter('isDefined', function() {
175
+ return function (input) {
176
+ return angular.isDefined(input);
177
+ }
178
+ })
179
+ .filter('isFunction', function() {
180
+ return function (input) {
181
+ return angular.isFunction(input);
182
+ }
183
+ })
184
+ .filter('isString', function() {
185
+ return function (input) {
186
+ return angular.isString(input)
187
+ }
188
+ })
189
+ .filter('isNumber', function() {
190
+ return function (input) {
191
+ return angular.isNumber(input);
192
+ }
193
+ })
194
+ .filter('isArray', function() {
195
+ return function (input) {
196
+ return angular.isArray(input);
197
+ }
198
+ })
199
+ .filter('isObject', function() {
200
+ return function (input) {
201
+ return angular.isObject(input);
202
+ }
203
+ })
204
+ .filter('isEqual', function() {
205
+ return function (o1, o2) {
206
+ return angular.equals(o1, o2);
207
+ }
208
+ });
209
+
210
+ /**
211
+ * @ngdoc filter
212
+ * @name a8m.conditions
213
+ * @kind function
214
+ *
215
+ * @description
216
+ * reference to math conditions
217
+ */
218
+ angular.module('a8m.conditions', [])
219
+
220
+ .filter({
221
+ isGreaterThan : isGreaterThanFilter,
222
+ '>' : isGreaterThanFilter,
223
+
224
+ isGreaterThanOrEqualTo : isGreaterThanOrEqualToFilter,
225
+ '>=' : isGreaterThanOrEqualToFilter,
226
+
227
+ isLessThan : isLessThanFilter,
228
+ '<' : isLessThanFilter,
229
+
230
+ isLessThanOrEqualTo : isLessThanOrEqualToFilter,
231
+ '<=' : isLessThanOrEqualToFilter,
232
+
233
+ isEqualTo : isEqualToFilter,
234
+ '==' : isEqualToFilter,
235
+
236
+ isNotEqualTo : isNotEqualToFilter,
237
+ '!=' : isNotEqualToFilter,
238
+
239
+ isIdenticalTo : isIdenticalToFilter,
240
+ '===' : isIdenticalToFilter,
241
+
242
+ isNotIdenticalTo : isNotIdenticalToFilter,
243
+ '!==' : isNotIdenticalToFilter
244
+ });
245
+
246
+ function isGreaterThanFilter() {
247
+ return function (input, check) {
248
+ return input > check;
249
+ };
250
+ }
251
+
252
+ function isGreaterThanOrEqualToFilter() {
253
+ return function (input, check) {
254
+ return input >= check;
255
+ };
256
+ }
257
+
258
+ function isLessThanFilter() {
259
+ return function (input, check) {
260
+ return input < check;
261
+ };
262
+ }
263
+
264
+ function isLessThanOrEqualToFilter() {
265
+ return function (input, check) {
266
+ return input <= check;
267
+ };
268
+ }
269
+
270
+ function isEqualToFilter() {
271
+ return function (input, check) {
272
+ return input == check;
273
+ };
274
+ }
275
+
276
+ function isNotEqualToFilter() {
277
+ return function (input, check) {
278
+ return input != check;
279
+ };
280
+ }
281
+
282
+ function isIdenticalToFilter() {
283
+ return function (input, check) {
284
+ return input === check;
285
+ };
286
+ }
287
+
288
+ function isNotIdenticalToFilter() {
289
+ return function (input, check) {
290
+ return input !== check;
291
+ };
292
+ }
293
+ /**
294
+ * @ngdoc filter
295
+ * @name isNull
296
+ * @kind function
297
+ *
298
+ * @description
299
+ * checks if value is null or not
300
+ * @return Boolean
301
+ */
302
+ angular.module('a8m.is-null', [])
303
+ .filter('isNull', function () {
304
+ return function(input) {
305
+ return isNull(input);
306
+ }
307
+ });
308
+
309
+ /**
310
+ * @ngdoc filter
311
+ * @name after-where
312
+ * @kind function
313
+ *
314
+ * @description
315
+ * get a collection and properties object, and returns all of the items
316
+ * in the collection after the first that found with the given properties.
317
+ *
318
+ */
319
+ angular.module('a8m.after-where', [])
320
+ .filter('afterWhere', function() {
321
+ return function (collection, object) {
322
+
323
+ collection = isObject(collection)
324
+ ? toArray(collection)
325
+ : collection;
326
+
327
+ if(!isArray(collection) || isUndefined(object)) return collection;
328
+
329
+ var index = collection.map( function( elm ) {
330
+ return objectContains(object, elm);
331
+ }).indexOf( true );
332
+
333
+ return collection.slice((index === -1) ? 0 : index);
334
+ }
335
+ });
336
+
337
+ /**
338
+ * @ngdoc filter
339
+ * @name after
340
+ * @kind function
341
+ *
342
+ * @description
343
+ * get a collection and specified count, and returns all of the items
344
+ * in the collection after the specified count.
345
+ *
346
+ */
347
+
348
+ angular.module('a8m.after', [])
349
+ .filter('after', function() {
350
+ return function (collection, count) {
351
+ collection = isObject(collection)
352
+ ? toArray(collection)
353
+ : collection;
354
+
355
+ return (isArray(collection))
356
+ ? collection.slice(count)
357
+ : collection;
358
+ }
359
+ });
360
+
361
+ /**
362
+ * @ngdoc filter
363
+ * @name before-where
364
+ * @kind function
365
+ *
366
+ * @description
367
+ * get a collection and properties object, and returns all of the items
368
+ * in the collection before the first that found with the given properties.
369
+ */
370
+ angular.module('a8m.before-where', [])
371
+ .filter('beforeWhere', function() {
372
+ return function (collection, object) {
373
+
374
+ collection = isObject(collection)
375
+ ? toArray(collection)
376
+ : collection;
377
+
378
+ if(!isArray(collection) || isUndefined(object)) return collection;
379
+
380
+ var index = collection.map( function( elm ) {
381
+ return objectContains(object, elm);
382
+ }).indexOf( true );
383
+
384
+ return collection.slice(0, (index === -1) ? collection.length : ++index);
385
+ }
386
+ });
387
+
388
+ /**
389
+ * @ngdoc filter
390
+ * @name before
391
+ * @kind function
392
+ *
393
+ * @description
394
+ * get a collection and specified count, and returns all of the items
395
+ * in the collection before the specified count.
396
+ */
397
+ angular.module('a8m.before', [])
398
+ .filter('before', function() {
399
+ return function (collection, count) {
400
+ collection = isObject(collection)
401
+ ? toArray(collection)
402
+ : collection;
403
+
404
+ return (isArray(collection))
405
+ ? collection.slice(0, (!count) ? count : --count)
406
+ : collection;
407
+ }
408
+ });
409
+
410
+ /**
411
+ * @ngdoc filter
412
+ * @name chunkBy
413
+ * @kind function
414
+ *
415
+ * @description
416
+ * Collect data into fixed-length chunks or blocks
417
+ */
418
+
419
+ angular.module('a8m.chunk-by', [])
420
+ .filter('chunkBy', [function () {
421
+ /**
422
+ * @description
423
+ * Get array with size `n` in `val` inside it.
424
+ * @param n
425
+ * @param val
426
+ * @returns {Array}
427
+ */
428
+ function fill(n, val) {
429
+ var ret = [];
430
+ while(n--) ret[n] = val;
431
+ return ret;
432
+ }
433
+
434
+ return function (array, n, fillVal) {
435
+ if (!isArray(array)) return array;
436
+ return array.map(function(el, i, self) {
437
+ i = i * n;
438
+ el = self.slice(i, i + n);
439
+ return !isUndefined(fillVal) && el.length < n
440
+ ? el.concat(fill(n - el.length, fillVal))
441
+ : el;
442
+ }).slice(0, Math.ceil(array.length / n));
443
+ }
444
+ }]);
445
+
446
+ /**
447
+ * @ngdoc filter
448
+ * @name concat
449
+ * @kind function
450
+ *
451
+ * @description
452
+ * get (array/object, object/array) and return merged collection
453
+ */
454
+ angular.module('a8m.concat', [])
455
+ .filter('concat', [function () {
456
+ return function (collection, joined) {
457
+
458
+ if (isUndefined(joined)) return collection;
459
+
460
+ if (isArray(collection)) {
461
+ return isObject(joined)
462
+ ? collection.concat(toArray(joined))
463
+ : collection.concat(joined);
464
+ }
465
+
466
+ if (isObject(collection)) {
467
+ var array = toArray(collection);
468
+ return (isObject(joined))
469
+ ? array.concat(toArray(joined))
470
+ : array.concat(joined);
471
+ }
472
+ return collection;
473
+ };
474
+ }
475
+ ]);
476
+
477
+ /**
478
+ * @ngdoc filter
479
+ * @name contains
480
+ * @kind function
481
+ *
482
+ * @description
483
+ * Checks if given expression is present in one or more object in the collection
484
+ */
485
+ angular.module('a8m.contains', [])
486
+ .filter({
487
+ contains: ['$parse', containsFilter],
488
+ some: ['$parse', containsFilter]
489
+ });
490
+
491
+ function containsFilter($parse) {
492
+ return function (collection, expression) {
493
+
494
+ collection = isObject(collection) ? toArray(collection) : collection;
495
+
496
+ if(!isArray(collection) || isUndefined(expression)) {
497
+ return false;
498
+ }
499
+
500
+ return collection.some(function(elm) {
501
+ return (isObject(elm) || isFunction(expression))
502
+ ? $parse(expression)(elm)
503
+ : elm === expression;
504
+ });
505
+
506
+ }
507
+ }
508
+
509
+ /**
510
+ * @ngdoc filter
511
+ * @name countBy
512
+ * @kind function
513
+ *
514
+ * @description
515
+ * Sorts a list into groups and returns a count for the number of objects in each group.
516
+ */
517
+
518
+ angular.module('a8m.count-by', [])
519
+
520
+ .filter('countBy', [ '$parse', function ( $parse ) {
521
+ return function (collection, property) {
522
+
523
+ var result = {},
524
+ get = $parse(property),
525
+ prop;
526
+
527
+ collection = (isObject(collection)) ? toArray(collection) : collection;
528
+
529
+ if(!isArray(collection) || isUndefined(property)) {
530
+ return collection;
531
+ }
532
+
533
+ collection.forEach( function( elm ) {
534
+ prop = get(elm);
535
+
536
+ if(!result[prop]) {
537
+ result[prop] = 0;
538
+ }
539
+
540
+ result[prop]++;
541
+ });
542
+
543
+ return result;
544
+ }
545
+ }]);
546
+
547
+ /**
548
+ * @ngdoc filter
549
+ * @name defaults
550
+ * @kind function
551
+ *
552
+ * @description
553
+ * defaultsFilter allows to specify a default fallback value for properties that resolve to undefined.
554
+ */
555
+ angular.module('a8m.defaults', [])
556
+ .filter('defaults', ['$parse', function( $parse ) {
557
+ return function(collection, defaults) {
558
+
559
+ collection = isObject(collection) ? toArray(collection) : collection;
560
+
561
+ if(!isArray(collection) || !isObject(defaults)) {
562
+ return collection;
563
+ }
564
+
565
+ var keys = deepKeys(defaults);
566
+
567
+ collection.forEach(function(elm) {
568
+ //loop through all the keys
569
+ keys.forEach(function(key) {
570
+ var getter = $parse(key);
571
+ var setter = getter.assign;
572
+ //if it's not exist
573
+ if(isUndefined(getter(elm))) {
574
+ //get from defaults, and set to the returned object
575
+ setter(elm, getter(defaults))
576
+ }
577
+ });
578
+ });
579
+
580
+ return collection;
581
+ }
582
+ }]);
583
+ /**
584
+ * @ngdoc filter
585
+ * @name every
586
+ * @kind function
587
+ *
588
+ * @description
589
+ * Checks if given expression is present in all members in the collection
590
+ *
591
+ */
592
+ angular.module('a8m.every', [])
593
+ .filter('every', ['$parse', function($parse) {
594
+ return function (collection, expression) {
595
+ collection = isObject(collection) ? toArray(collection) : collection;
596
+
597
+ if(!isArray(collection) || isUndefined(expression)) {
598
+ return true;
599
+ }
600
+
601
+ return collection.every( function(elm) {
602
+ return (isObject(elm) || isFunction(expression))
603
+ ? $parse(expression)(elm)
604
+ : elm === expression;
605
+ });
606
+ }
607
+ }]);
608
+
609
+ /**
610
+ * @ngdoc filter
611
+ * @name filterBy
612
+ * @kind function
613
+ *
614
+ * @description
615
+ * filter by specific properties, avoid the rest
616
+ */
617
+ angular.module('a8m.filter-by', [])
618
+ .filter('filterBy', ['$parse', function( $parse ) {
619
+ return function(collection, properties, search) {
620
+ var comparator;
621
+
622
+ search = (isString(search) || isNumber(search)) ?
623
+ String(search).toLowerCase() : undefined;
624
+
625
+ collection = isObject(collection) ? toArray(collection) : collection;
626
+
627
+ if(!isArray(collection) || isUndefined(search)) {
628
+ return collection;
629
+ }
630
+
631
+ return collection.filter(function(elm) {
632
+ return properties.some(function(prop) {
633
+
634
+ /**
635
+ * check if there is concatenate properties
636
+ * example:
637
+ * object: { first: 'foo', last:'bar' }
638
+ * filterBy: ['first + last'] => search by full name(i.e 'foo bar')
639
+ */
640
+ if(!~prop.indexOf('+')) {
641
+ comparator = $parse(prop)(elm)
642
+ } else {
643
+ var propList = prop.replace(new RegExp('\\s', 'g'), '').split('+');
644
+ comparator = propList.reduce(function(prev, cur, index) {
645
+ return (index === 1) ? $parse(prev)(elm) + ' ' + $parse(cur)(elm) :
646
+ prev + ' ' + $parse(cur)(elm);
647
+ });
648
+ }
649
+
650
+ return (isString(comparator) || isNumber(comparator))
651
+ ? String(comparator).toLowerCase().contains(search)
652
+ : false;
653
+ });
654
+ });
655
+ }
656
+ }]);
657
+
658
+ /**
659
+ * @ngdoc filter
660
+ * @name first
661
+ * @kind function
662
+ *
663
+ * @description
664
+ * Gets the first element or first n elements of an array
665
+ * if callback is provided, is returns as long the callback return truthy
666
+ */
667
+ angular.module('a8m.first', [])
668
+ .filter('first', ['$parse', function( $parse ) {
669
+ return function(collection) {
670
+ var n
671
+ , getter
672
+ , args;
673
+
674
+ collection = isObject(collection)
675
+ ? toArray(collection)
676
+ : collection;
677
+
678
+ if(!isArray(collection)) {
679
+ return collection;
680
+ }
681
+
682
+ args = Array.prototype.slice.call(arguments, 1);
683
+ n = (isNumber(args[0])) ? args[0] : 1;
684
+ getter = (!isNumber(args[0])) ? args[0] : (!isNumber(args[1])) ? args[1] : undefined;
685
+
686
+ return (args.length) ? getFirstMatches(collection, n,(getter) ? $parse(getter) : getter) :
687
+ collection[0];
688
+ }
689
+ }]);
690
+
691
+ /**
692
+ * @ngdoc filter
693
+ * @name flatten
694
+ * @kind function
695
+ *
696
+ * @description
697
+ * Flattens a nested array (the nesting can be to any depth).
698
+ * If you pass shallow, the array will only be flattened a single level
699
+ */
700
+ angular.module('a8m.flatten', [])
701
+ .filter('flatten', function () {
702
+ return function(collection, shallow) {
703
+
704
+ shallow = shallow || false;
705
+ collection = isObject(collection)
706
+ ? toArray(collection)
707
+ : collection;
708
+
709
+ if(!isArray(collection)) {
710
+ return collection;
711
+ }
712
+
713
+ return !shallow
714
+ ? flatten(collection, 0)
715
+ : [].concat.apply([], collection);
716
+ }
717
+ });
718
+
719
+ /**
720
+ * flatten nested array (the nesting can be to any depth).
721
+ * @param array {Array}
722
+ * @param i {int}
723
+ * @returns {Array}
724
+ * @private
725
+ */
726
+ function flatten(array, i) {
727
+ i = i || 0;
728
+
729
+ if(i >= array.length)
730
+ return array;
731
+
732
+ if(isArray(array[i])) {
733
+ return flatten(array.slice(0,i)
734
+ .concat(array[i], array.slice(i+1)), i);
735
+ }
736
+ return flatten(array, i+1);
737
+ }
738
+
739
+ /**
740
+ * @ngdoc filter
741
+ * @name fuzzyByKey
742
+ * @kind function
743
+ *
744
+ * @description
745
+ * fuzzy string searching by key
746
+ */
747
+ angular.module('a8m.fuzzy-by', [])
748
+ .filter('fuzzyBy', ['$parse', function ( $parse ) {
749
+ return function (collection, property, search, csensitive) {
750
+
751
+ var sensitive = csensitive || false,
752
+ prop, getter;
753
+
754
+ collection = isObject(collection) ? toArray(collection) : collection;
755
+
756
+ if(!isArray(collection) || isUndefined(property)
757
+ || isUndefined(search)) {
758
+ return collection;
759
+ }
760
+
761
+ getter = $parse(property);
762
+
763
+ return collection.filter(function(elm) {
764
+
765
+ prop = getter(elm);
766
+ if(!isString(prop)) {
767
+ return false;
768
+ }
769
+
770
+ prop = (sensitive) ? prop : prop.toLowerCase();
771
+ search = (sensitive) ? search : search.toLowerCase();
772
+
773
+ return hasApproxPattern(prop, search) !== false
774
+ })
775
+ }
776
+
777
+ }]);
778
+ /**
779
+ * @ngdoc filter
780
+ * @name fuzzy
781
+ * @kind function
782
+ *
783
+ * @description
784
+ * fuzzy string searching for array of strings, objects
785
+ */
786
+ angular.module('a8m.fuzzy', [])
787
+ .filter('fuzzy', function () {
788
+ return function (collection, search, csensitive) {
789
+ var sensitive = csensitive || false;
790
+ collection = isObject(collection) ? toArray(collection) : collection;
791
+
792
+ if(!isArray(collection) || isUndefined(search)) {
793
+ return collection;
794
+ }
795
+
796
+ search = (sensitive) ? search : search.toLowerCase();
797
+
798
+ return collection.filter(function(elm) {
799
+ if(isString(elm)) {
800
+ elm = (sensitive) ? elm : elm.toLowerCase();
801
+ return hasApproxPattern(elm, search) !== false
802
+ }
803
+ return (isObject(elm)) ? _hasApproximateKey(elm, search) : false;
804
+ });
805
+
806
+ /**
807
+ * checks if object has key{string} that match
808
+ * to fuzzy search pattern
809
+ * @param object
810
+ * @param search
811
+ * @returns {boolean}
812
+ * @private
813
+ */
814
+ function _hasApproximateKey(object, search) {
815
+ var properties = Object.keys(object),
816
+ prop, flag;
817
+ return 0 < properties.filter(function (elm) {
818
+ prop = object[elm];
819
+
820
+ //avoid iteration if we found some key that equal[performance]
821
+ if(flag) return true;
822
+
823
+ if (isString(prop)) {
824
+ prop = (sensitive) ? prop : prop.toLowerCase();
825
+ return flag = (hasApproxPattern(prop, search) !== false);
826
+ }
827
+
828
+ return false;
829
+
830
+ }).length;
831
+ }
832
+ }
833
+ });
834
+
835
+ /**
836
+ * @ngdoc filter
837
+ * @name groupBy
838
+ * @kind function
839
+ *
840
+ * @description
841
+ * Create an object composed of keys generated from the result of running each element of a collection,
842
+ * each key is an array of the elements.
843
+ */
844
+
845
+ angular.module('a8m.group-by', [ 'a8m.filter-watcher' ])
846
+ .filter('groupBy', [ '$parse', 'filterWatcher', function ( $parse, filterWatcher ) {
847
+ return function (collection, property) {
848
+
849
+ if(!isObject(collection) || isUndefined(property)) {
850
+ return collection;
851
+ }
852
+
853
+ var getterFn = $parse(property);
854
+
855
+ return filterWatcher.isMemoized('groupBy', arguments) ||
856
+ filterWatcher.memoize('groupBy', arguments, this,
857
+ _groupBy(collection, getterFn));
858
+
859
+ /**
860
+ * groupBy function
861
+ * @param collection
862
+ * @param getter
863
+ * @returns {{}}
864
+ */
865
+ function _groupBy(collection, getter) {
866
+ var result = {};
867
+ var prop;
868
+
869
+ forEach( collection, function( elm ) {
870
+ prop = getter(elm);
871
+
872
+ if(!result[prop]) {
873
+ result[prop] = [];
874
+ }
875
+ result[prop].push(elm);
876
+ });
877
+ return result;
878
+ }
879
+ }
880
+ }]);
881
+
882
+ /**
883
+ * @ngdoc filter
884
+ * @name isEmpty
885
+ * @kind function
886
+ *
887
+ * @description
888
+ * get collection or string and return if it empty
889
+ */
890
+ angular.module('a8m.is-empty', [])
891
+ .filter('isEmpty', function () {
892
+ return function(collection) {
893
+ return isObject(collection)
894
+ ? !toArray(collection).length
895
+ : !collection.length;
896
+ }
897
+ });
898
+
899
+ /**
900
+ * @ngdoc filter
901
+ * @name join
902
+ * @kind function
903
+ *
904
+ * @description
905
+ * join a collection by a provided delimiter (space by default)
906
+ */
907
+ angular.module('a8m.join', [])
908
+ .filter('join', function () {
909
+ return function (input, delimiter) {
910
+ if (isUndefined(input) || !isArray(input)) {
911
+ return input;
912
+ }
913
+ if (isUndefined(delimiter)) delimiter = ' ';
914
+
915
+ return input.join(delimiter);
916
+ };
917
+ })
918
+ ;
919
+
920
+ /**
921
+ * @ngdoc filter
922
+ * @name last
923
+ * @kind function
924
+ *
925
+ * @description
926
+ * Gets the last element or last n elements of an array
927
+ * if callback is provided, is returns as long the callback return truthy
928
+ */
929
+ angular.module('a8m.last', [])
930
+ .filter('last', ['$parse', function( $parse ) {
931
+ return function(collection) {
932
+ var n
933
+ , getter
934
+ , args
935
+ //cuz reverse change our src collection
936
+ //and we don't want side effects
937
+ , reversed = copy(collection);
938
+
939
+ reversed = isObject(reversed)
940
+ ? toArray(reversed)
941
+ : reversed;
942
+
943
+ if(!isArray(reversed)) {
944
+ return reversed;
945
+ }
946
+
947
+ args = Array.prototype.slice.call(arguments, 1);
948
+ n = (isNumber(args[0])) ? args[0] : 1;
949
+ getter = (!isNumber(args[0])) ? args[0] : (!isNumber(args[1])) ? args[1] : undefined;
950
+
951
+ return (args.length)
952
+ //send reversed collection as arguments, and reverse it back as result
953
+ ? getFirstMatches(reversed.reverse(), n,(getter) ? $parse(getter) : getter).reverse()
954
+ //get the last element
955
+ : reversed[reversed.length-1];
956
+ }
957
+ }]);
958
+
959
+ /**
960
+ * @ngdoc filter
961
+ * @name map
962
+ * @kind function
963
+ *
964
+ * @description
965
+ * Returns a new collection of the results of each expression execution.
966
+ */
967
+ angular.module('a8m.map', [])
968
+ .filter('map', ['$parse', function($parse) {
969
+ return function (collection, expression) {
970
+
971
+ collection = isObject(collection)
972
+ ? toArray(collection)
973
+ : collection;
974
+
975
+ if(!isArray(collection) || isUndefined(expression)) {
976
+ return collection;
977
+ }
978
+
979
+ return collection.map(function (elm) {
980
+ return $parse(expression)(elm);
981
+ });
982
+ }
983
+ }]);
984
+
985
+ /**
986
+ * @ngdoc filter
987
+ * @name omit
988
+ * @kind function
989
+ *
990
+ * @description
991
+ * filter collection by expression
992
+ */
993
+
994
+ angular.module('a8m.omit', [])
995
+
996
+ .filter('omit', ['$parse', function($parse) {
997
+ return function (collection, expression) {
998
+
999
+ collection = isObject(collection)
1000
+ ? toArray(collection)
1001
+ : collection;
1002
+
1003
+ if(!isArray(collection) || isUndefined(expression)) {
1004
+ return collection;
1005
+ }
1006
+
1007
+ return collection.filter(function (elm) {
1008
+ return !($parse(expression)(elm));
1009
+ });
1010
+ }
1011
+ }]);
1012
+
1013
+ /**
1014
+ * @ngdoc filter
1015
+ * @name pick
1016
+ * @kind function
1017
+ *
1018
+ * @description
1019
+ * filter collection by expression
1020
+ */
1021
+
1022
+ angular.module('a8m.pick', [])
1023
+
1024
+ .filter('pick', ['$parse', function($parse) {
1025
+ return function (collection, expression) {
1026
+
1027
+ collection = isObject(collection)
1028
+ ? toArray(collection)
1029
+ : collection;
1030
+
1031
+ if(!isArray(collection) || isUndefined(expression)) {
1032
+ return collection;
1033
+ }
1034
+
1035
+ return collection.filter(function (elm) {
1036
+ return $parse(expression)(elm);
1037
+ });
1038
+ }
1039
+ }]);
1040
+
1041
+ /**
1042
+ * @ngdoc filter
1043
+ * @name range
1044
+ * @kind function
1045
+ *
1046
+ * @description
1047
+ * rangeFilter provides some support for a for loop using numbers
1048
+ */
1049
+ angular.module('a8m.range', [])
1050
+ .filter('range', function () {
1051
+ return function (input, total) {
1052
+ for (var i = 0; i < parseInt(total); i++) {
1053
+ input.push(i);
1054
+ }
1055
+ return input;
1056
+ };
1057
+ });
1058
+ /**
1059
+ * @ngdoc filter
1060
+ * @name removeWith
1061
+ * @kind function
1062
+ *
1063
+ * @description
1064
+ * get collection and properties object, and removed elements
1065
+ * with this properties
1066
+ */
1067
+
1068
+ angular.module('a8m.remove-with', [])
1069
+ .filter('removeWith', function() {
1070
+ return function (collection, object) {
1071
+
1072
+ if(isUndefined(object)) {
1073
+ return collection;
1074
+ }
1075
+ collection = isObject(collection)
1076
+ ? toArray(collection)
1077
+ : collection;
1078
+
1079
+ return collection.filter(function (elm) {
1080
+ return !objectContains(object, elm);
1081
+ });
1082
+ }
1083
+ });
1084
+
1085
+
1086
+ /**
1087
+ * @ngdoc filter
1088
+ * @name remove
1089
+ * @kind function
1090
+ *
1091
+ * @description
1092
+ * remove specific members from collection
1093
+ */
1094
+
1095
+ angular.module('a8m.remove', [])
1096
+
1097
+ .filter('remove', function () {
1098
+ return function (collection) {
1099
+ collection = isObject(collection) ? toArray(collection) : collection;
1100
+ var args = Array.prototype.slice.call(arguments, 1);
1101
+
1102
+ if(!isArray(collection)) {
1103
+ return collection;
1104
+ }
1105
+
1106
+ return collection.filter( function( member ) {
1107
+ return !args.some(function(nest) {
1108
+ return equals(nest, member);
1109
+ })
1110
+ });
1111
+ }
1112
+ });
1113
+
1114
+ /**
1115
+ * @ngdoc filter
1116
+ * @name reverse
1117
+ * @kind function
1118
+ *
1119
+ * @description
1120
+ * Reverses a string or collection
1121
+ */
1122
+ angular.module('a8m.reverse', [])
1123
+ .filter('reverse',[ function () {
1124
+ return function (input) {
1125
+ input = isObject(input) ? toArray(input) : input;
1126
+
1127
+ if(isString(input)) {
1128
+ return input.split('').reverse().join('');
1129
+ }
1130
+
1131
+ return isArray(input)
1132
+ ? input.slice().reverse()
1133
+ : input;
1134
+ }
1135
+ }]);
1136
+
1137
+ /**
1138
+ * @ngdoc filter
1139
+ * @name searchField
1140
+ * @kind function
1141
+ *
1142
+ * @description
1143
+ * for each member, join several strings field and add them to
1144
+ * new field called 'searchField' (use for search filtering)
1145
+ */
1146
+ angular.module('a8m.search-field', [])
1147
+ .filter('searchField', ['$parse', function ($parse) {
1148
+ return function (collection) {
1149
+
1150
+ var get, field;
1151
+
1152
+ collection = isObject(collection) ? toArray(collection) : collection;
1153
+
1154
+ var args = Array.prototype.slice.call(arguments, 1);
1155
+
1156
+ if(!isArray(collection) || !args.length) {
1157
+ return collection;
1158
+ }
1159
+
1160
+ return collection.map(function(member) {
1161
+
1162
+ field = args.map(function(field) {
1163
+ get = $parse(field);
1164
+ return get(member);
1165
+ }).join(' ');
1166
+
1167
+ return extend(member, { searchField: field });
1168
+ });
1169
+ }
1170
+ }]);
1171
+
1172
+ /**
1173
+ * @ngdoc filter
1174
+ * @name toArray
1175
+ * @kind function
1176
+ *
1177
+ * @description
1178
+ * Convert objects into stable arrays.
1179
+ * if addKey set to true,the filter also attaches a new property
1180
+ * $key to the value containing the original key that was used in
1181
+ * the object we are iterating over to reference the property
1182
+ */
1183
+ angular.module('a8m.to-array', [])
1184
+ .filter('toArray', function() {
1185
+ return function (collection, addKey) {
1186
+
1187
+ if(!isObject(collection)) {
1188
+ return collection;
1189
+ }
1190
+
1191
+ return !addKey
1192
+ ? toArray(collection)
1193
+ : Object.keys(collection).map(function (key) {
1194
+ return extend(collection[key], { $key: key });
1195
+ });
1196
+ }
1197
+ });
1198
+
1199
+ /**
1200
+ * @ngdoc filter
1201
+ * @name unique/uniq
1202
+ * @kind function
1203
+ *
1204
+ * @description
1205
+ * get collection and filter duplicate members
1206
+ * if uniqueFilter get a property(nested to) as argument it's
1207
+ * filter by this property as unique identifier
1208
+ */
1209
+
1210
+ angular.module('a8m.unique', [])
1211
+ .filter({
1212
+ unique: ['$parse', uniqFilter],
1213
+ uniq: ['$parse', uniqFilter]
1214
+ });
1215
+
1216
+ function uniqFilter($parse) {
1217
+ return function (collection, property) {
1218
+
1219
+ collection = isObject(collection) ? toArray(collection) : collection;
1220
+
1221
+ if (!isArray(collection)) {
1222
+ return collection;
1223
+ }
1224
+
1225
+ //store all unique identifiers
1226
+ var uniqueItems = [],
1227
+ get = $parse(property);
1228
+
1229
+ return (isUndefined(property))
1230
+ //if it's kind of primitive array
1231
+ ? collection.filter(function (elm, pos, self) {
1232
+ return self.indexOf(elm) === pos;
1233
+ })
1234
+ //else compare with equals
1235
+ : collection.filter(function (elm) {
1236
+ var prop = get(elm);
1237
+ if(some(uniqueItems, prop)) {
1238
+ return false;
1239
+ }
1240
+ uniqueItems.push(prop);
1241
+ return true;
1242
+ });
1243
+
1244
+ //checked if the unique identifier is already exist
1245
+ function some(array, member) {
1246
+ if(isUndefined(member)) {
1247
+ return false;
1248
+ }
1249
+ return array.some(function(el) {
1250
+ return equals(el, member);
1251
+ });
1252
+ }
1253
+ }
1254
+ }
1255
+
1256
+ /**
1257
+ * @ngdoc filter
1258
+ * @name where
1259
+ * @kind function
1260
+ *
1261
+ * @description
1262
+ * of each element in a collection to the given properties object,
1263
+ * returning an array of all elements that have equivalent property values.
1264
+ *
1265
+ */
1266
+ angular.module('a8m.where', [])
1267
+ .filter('where', function() {
1268
+ return function (collection, object) {
1269
+ if(isUndefined(object)) return collection;
1270
+ collection = isObject(collection)
1271
+ ? toArray(collection)
1272
+ : collection;
1273
+
1274
+ return collection.filter(function (elm) {
1275
+ return objectContains(object, elm);
1276
+ });
1277
+ }
1278
+ });
1279
+
1280
+ /**
1281
+ * @ngdoc filter
1282
+ * @name xor
1283
+ * @kind function
1284
+ *
1285
+ * @description
1286
+ * Exclusive or filter by expression
1287
+ */
1288
+
1289
+ angular.module('a8m.xor', [])
1290
+
1291
+ .filter('xor', ['$parse', function($parse) {
1292
+ return function (col1, col2, expression) {
1293
+
1294
+ expression = expression || false;
1295
+
1296
+ col1 = isObject(col1) ? toArray(col1) : col1;
1297
+ col2 = isObject(col2) ? toArray(col2) : col2;
1298
+
1299
+ if(!isArray(col1) || !isArray(col2)) return col1;
1300
+
1301
+ return col1.concat(col2)
1302
+ .filter(function(elm) {
1303
+ return !(some(elm, col1) && some(elm, col2));
1304
+ });
1305
+
1306
+ function some(el, col) {
1307
+ var getter = $parse(expression);
1308
+ return col.some(function(dElm) {
1309
+ return expression
1310
+ ? equals(getter(dElm), getter(el))
1311
+ : equals(dElm, el);
1312
+ });
1313
+ }
1314
+ }
1315
+ }]);
1316
+
1317
+ /**
1318
+ * @ngdoc filter
1319
+ * @name formatBytes
1320
+ * @kind function
1321
+ *
1322
+ * @description
1323
+ * Convert bytes into appropriate display
1324
+ * 1024 bytes => 1 KB
1325
+ */
1326
+ angular.module('a8m.math.byteFmt', ['a8m.math'])
1327
+ .filter('byteFmt', ['$math', function ($math) {
1328
+ return function (bytes, decimal) {
1329
+
1330
+ if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
1331
+ isNumber(bytes) && isFinite(bytes)) {
1332
+ if(bytes < 1024) { // within 1 KB so B
1333
+ return convertToDecimal(bytes, decimal, $math) + ' B';
1334
+ } else if(bytes < 1048576) { // within 1 MB so KB
1335
+ return convertToDecimal((bytes / 1024), decimal, $math) + ' KB';
1336
+ } else if(bytes < 1073741824){ // within 1 GB so MB
1337
+ return convertToDecimal((bytes / 1048576), decimal, $math) + ' MB';
1338
+ } else { // GB or more
1339
+ return convertToDecimal((bytes / 1073741824), decimal, $math) + ' GB';
1340
+ }
1341
+
1342
+ }
1343
+ return "NaN";
1344
+ }
1345
+ }]);
1346
+ /**
1347
+ * @ngdoc filter
1348
+ * @name degrees
1349
+ * @kind function
1350
+ *
1351
+ * @description
1352
+ * Convert angle from radians to degrees
1353
+ */
1354
+ angular.module('a8m.math.degrees', ['a8m.math'])
1355
+ .filter('degrees', ['$math', function ($math) {
1356
+ return function (radians, decimal) {
1357
+ // if decimal is not an integer greater than -1, we cannot do. quit with error "NaN"
1358
+ // if degrees is not a real number, we cannot do also. quit with error "NaN"
1359
+ if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
1360
+ isNumber(radians) && isFinite(radians)) {
1361
+ var degrees = (radians * 180) / $math.PI;
1362
+ return $math.round(degrees * $math.pow(10,decimal)) / ($math.pow(10,decimal));
1363
+ } else {
1364
+ return "NaN";
1365
+ }
1366
+ }
1367
+ }]);
1368
+
1369
+
1370
+
1371
+ /**
1372
+ * @ngdoc filter
1373
+ * @name formatBytes
1374
+ * @kind function
1375
+ *
1376
+ * @description
1377
+ * Convert bytes into appropriate display
1378
+ * 1024 kilobytes => 1 MB
1379
+ */
1380
+ angular.module('a8m.math.kbFmt', ['a8m.math'])
1381
+ .filter('kbFmt', ['$math', function ($math) {
1382
+ return function (bytes, decimal) {
1383
+
1384
+ if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
1385
+ isNumber(bytes) && isFinite(bytes)) {
1386
+ if(bytes < 1024) { // within 1 MB so KB
1387
+ return convertToDecimal(bytes, decimal, $math) + ' KB';
1388
+ } else if(bytes < 1048576) { // within 1 GB so MB
1389
+ return convertToDecimal((bytes / 1024), decimal, $math) + ' MB';
1390
+ } else {
1391
+ return convertToDecimal((bytes / 1048576), decimal, $math) + ' GB';
1392
+ }
1393
+ }
1394
+ return "NaN";
1395
+ }
1396
+ }]);
1397
+ /**
1398
+ * @ngdoc module
1399
+ * @name math
1400
+ * @description
1401
+ * reference to global Math object
1402
+ */
1403
+ angular.module('a8m.math', [])
1404
+ .factory('$math', ['$window', function ($window) {
1405
+ return $window.Math;
1406
+ }]);
1407
+
1408
+ /**
1409
+ * @ngdoc filter
1410
+ * @name max
1411
+ * @kind function
1412
+ *
1413
+ * @description
1414
+ * Math.max will get an array and return the max value. if an expression
1415
+ * is provided, will return max value by expression.
1416
+ */
1417
+ angular.module('a8m.math.max', ['a8m.math'])
1418
+ .filter('max', ['$math', '$parse', function ($math, $parse) {
1419
+ return function (input, expression) {
1420
+
1421
+ if(!isArray(input)) {
1422
+ return input;
1423
+ }
1424
+ return isUndefined(expression)
1425
+ ? $math.max.apply($math, input)
1426
+ : input[indexByMax(input, expression)];
1427
+ };
1428
+
1429
+ /**
1430
+ * @private
1431
+ * @param array
1432
+ * @param exp
1433
+ * @returns {number|*|Number}
1434
+ */
1435
+ function indexByMax(array, exp) {
1436
+ var mappedArray = array.map(function(elm){
1437
+ return $parse(exp)(elm);
1438
+ });
1439
+ return mappedArray.indexOf($math.max.apply($math, mappedArray));
1440
+ }
1441
+ }]);
1442
+ /**
1443
+ * @ngdoc filter
1444
+ * @name min
1445
+ * @kind function
1446
+ *
1447
+ * @description
1448
+ * Math.min will get an array and return the min value. if an expression
1449
+ * is provided, will return min value by expression.
1450
+ */
1451
+ angular.module('a8m.math.min', ['a8m.math'])
1452
+ .filter('min', ['$math', '$parse', function ($math, $parse) {
1453
+ return function (input, expression) {
1454
+
1455
+ if(!isArray(input)) {
1456
+ return input;
1457
+ }
1458
+ return isUndefined(expression)
1459
+ ? $math.min.apply($math, input)
1460
+ : input[indexByMin(input, expression)];
1461
+ };
1462
+
1463
+ /**
1464
+ * @private
1465
+ * @param array
1466
+ * @param exp
1467
+ * @returns {number|*|Number}
1468
+ */
1469
+ function indexByMin(array, exp) {
1470
+ var mappedArray = array.map(function(elm){
1471
+ return $parse(exp)(elm);
1472
+ });
1473
+ return mappedArray.indexOf($math.min.apply($math, mappedArray));
1474
+ }
1475
+ }]);
1476
+ /**
1477
+ * @ngdoc filter
1478
+ * @name Percent
1479
+ * @kind function
1480
+ *
1481
+ * @description
1482
+ * percentage between two numbers
1483
+ */
1484
+ angular.module('a8m.math.percent', ['a8m.math'])
1485
+ .filter('percent', ['$math', '$window', function ($math, $window) {
1486
+ return function (input, divided, round) {
1487
+
1488
+ var divider = isString(input) ? $window.Number(input) : input;
1489
+ divided = divided || 100;
1490
+ round = round || false;
1491
+
1492
+ if (!isNumber(divider) || $window.isNaN(divider)) return input;
1493
+
1494
+ return round
1495
+ ? $math.round((divider / divided) * 100)
1496
+ : (divider / divided) * 100;
1497
+ }
1498
+ }]);
1499
+
1500
+ /**
1501
+ * @ngdoc filter
1502
+ * @name toRadians
1503
+ * @kind function
1504
+ *
1505
+ * @description
1506
+ * Convert angle from degrees to radians
1507
+ */
1508
+ angular.module('a8m.math.radians', ['a8m.math'])
1509
+ .filter('radians', ['$math', function ($math) {
1510
+ return function (degrees, decimal) {
1511
+ // if decimal is not an integer greater than -1, we cannot do. quit with error "NaN"
1512
+ // if degrees is not a real number, we cannot do also. quit with error "NaN"
1513
+ if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
1514
+ isNumber(degrees) && isFinite(degrees)) {
1515
+ var radians = (degrees * 3.14159265359) / 180;
1516
+ return $math.round(radians * $math.pow(10,decimal)) / ($math.pow(10,decimal));
1517
+ }
1518
+ return "NaN";
1519
+ }
1520
+ }]);
1521
+
1522
+
1523
+
1524
+ /**
1525
+ * @ngdoc filter
1526
+ * @name Radix
1527
+ * @kind function
1528
+ *
1529
+ * @description
1530
+ * converting decimal numbers to different bases(radix)
1531
+ */
1532
+ angular.module('a8m.math.radix', [])
1533
+ .filter('radix', function () {
1534
+ return function (input, radix) {
1535
+ var RANGE = /^[2-9]$|^[1-2]\d$|^3[0-6]$/;
1536
+
1537
+ if(!isNumber(input) || !RANGE.test(radix)) {
1538
+ return input;
1539
+ }
1540
+
1541
+ return input.toString(radix).toUpperCase();
1542
+ }
1543
+ });
1544
+
1545
+ /**
1546
+ * @ngdoc filter
1547
+ * @name formatBytes
1548
+ * @kind function
1549
+ *
1550
+ * @description
1551
+ * Convert number into abbreviations.
1552
+ * i.e: K for one thousand, M for Million, B for billion
1553
+ * e.g: number of users:235,221, decimal:1 => 235.2 K
1554
+ */
1555
+ angular.module('a8m.math.shortFmt', ['a8m.math'])
1556
+ .filter('shortFmt', ['$math', function ($math) {
1557
+ return function (number, decimal) {
1558
+ if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
1559
+ isNumber(number) && isFinite(number)){
1560
+ if(number < 1e3) {
1561
+ return number;
1562
+ } else if(number < 1e6) {
1563
+ return convertToDecimal((number / 1e3), decimal, $math) + ' K';
1564
+ } else if(number < 1e9){
1565
+ return convertToDecimal((number / 1e6), decimal, $math) + ' M';
1566
+ } else {
1567
+ return convertToDecimal((number / 1e9), decimal, $math) + ' B';
1568
+ }
1569
+
1570
+ }
1571
+ return "NaN";
1572
+ }
1573
+ }]);
1574
+ /**
1575
+ * @ngdoc filter
1576
+ * @name sum
1577
+ * @kind function
1578
+ *
1579
+ * @description
1580
+ * Sum up all values within an array
1581
+ */
1582
+ angular.module('a8m.math.sum', [])
1583
+ .filter('sum', function () {
1584
+ return function (input, initial) {
1585
+ return !isArray(input)
1586
+ ? input
1587
+ : input.reduce(function(prev, curr) {
1588
+ return prev + curr;
1589
+ }, initial || 0);
1590
+ }
1591
+ });
1592
+
1593
+ /**
1594
+ * @ngdoc filter
1595
+ * @name endsWith
1596
+ * @kind function
1597
+ *
1598
+ * @description
1599
+ * checks whether string ends with the ends parameter.
1600
+ */
1601
+ angular.module('a8m.ends-with', [])
1602
+
1603
+ .filter('endsWith', function () {
1604
+ return function (input, ends, csensitive) {
1605
+
1606
+ var sensitive = csensitive || false,
1607
+ position;
1608
+
1609
+ if(!isString(input) || isUndefined(ends)) {
1610
+ return input;
1611
+ }
1612
+
1613
+ input = (sensitive) ? input : input.toLowerCase();
1614
+ position = input.length - ends.length;
1615
+
1616
+ return input.indexOf((sensitive) ? ends : ends.toLowerCase(), position) !== -1;
1617
+ }
1618
+ });
1619
+
1620
+ /**
1621
+ * @ngdoc filter
1622
+ * @name latinize
1623
+ * @kind function
1624
+ *
1625
+ * @description
1626
+ * remove accents/diacritics from a string
1627
+ */
1628
+ angular.module('a8m.latinize', [])
1629
+ .filter('latinize',[ function () {
1630
+ var defaultDiacriticsRemovalap = [
1631
+ {'base':'A', 'letters':'\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F'},
1632
+ {'base':'AA','letters':'\uA732'},
1633
+ {'base':'AE','letters':'\u00C6\u01FC\u01E2'},
1634
+ {'base':'AO','letters':'\uA734'},
1635
+ {'base':'AU','letters':'\uA736'},
1636
+ {'base':'AV','letters':'\uA738\uA73A'},
1637
+ {'base':'AY','letters':'\uA73C'},
1638
+ {'base':'B', 'letters':'\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181'},
1639
+ {'base':'C', 'letters':'\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E'},
1640
+ {'base':'D', 'letters':'\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779'},
1641
+ {'base':'DZ','letters':'\u01F1\u01C4'},
1642
+ {'base':'Dz','letters':'\u01F2\u01C5'},
1643
+ {'base':'E', 'letters':'\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E'},
1644
+ {'base':'F', 'letters':'\u0046\u24BB\uFF26\u1E1E\u0191\uA77B'},
1645
+ {'base':'G', 'letters':'\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E'},
1646
+ {'base':'H', 'letters':'\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D'},
1647
+ {'base':'I', 'letters':'\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197'},
1648
+ {'base':'J', 'letters':'\u004A\u24BF\uFF2A\u0134\u0248'},
1649
+ {'base':'K', 'letters':'\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2'},
1650
+ {'base':'L', 'letters':'\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780'},
1651
+ {'base':'LJ','letters':'\u01C7'},
1652
+ {'base':'Lj','letters':'\u01C8'},
1653
+ {'base':'M', 'letters':'\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C'},
1654
+ {'base':'N', 'letters':'\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4'},
1655
+ {'base':'NJ','letters':'\u01CA'},
1656
+ {'base':'Nj','letters':'\u01CB'},
1657
+ {'base':'O', 'letters':'\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C'},
1658
+ {'base':'OI','letters':'\u01A2'},
1659
+ {'base':'OO','letters':'\uA74E'},
1660
+ {'base':'OU','letters':'\u0222'},
1661
+ {'base':'OE','letters':'\u008C\u0152'},
1662
+ {'base':'oe','letters':'\u009C\u0153'},
1663
+ {'base':'P', 'letters':'\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754'},
1664
+ {'base':'Q', 'letters':'\u0051\u24C6\uFF31\uA756\uA758\u024A'},
1665
+ {'base':'R', 'letters':'\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782'},
1666
+ {'base':'S', 'letters':'\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784'},
1667
+ {'base':'T', 'letters':'\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786'},
1668
+ {'base':'TZ','letters':'\uA728'},
1669
+ {'base':'U', 'letters':'\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244'},
1670
+ {'base':'V', 'letters':'\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245'},
1671
+ {'base':'VY','letters':'\uA760'},
1672
+ {'base':'W', 'letters':'\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72'},
1673
+ {'base':'X', 'letters':'\u0058\u24CD\uFF38\u1E8A\u1E8C'},
1674
+ {'base':'Y', 'letters':'\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE'},
1675
+ {'base':'Z', 'letters':'\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762'},
1676
+ {'base':'a', 'letters':'\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250'},
1677
+ {'base':'aa','letters':'\uA733'},
1678
+ {'base':'ae','letters':'\u00E6\u01FD\u01E3'},
1679
+ {'base':'ao','letters':'\uA735'},
1680
+ {'base':'au','letters':'\uA737'},
1681
+ {'base':'av','letters':'\uA739\uA73B'},
1682
+ {'base':'ay','letters':'\uA73D'},
1683
+ {'base':'b', 'letters':'\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253'},
1684
+ {'base':'c', 'letters':'\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184'},
1685
+ {'base':'d', 'letters':'\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A'},
1686
+ {'base':'dz','letters':'\u01F3\u01C6'},
1687
+ {'base':'e', 'letters':'\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD'},
1688
+ {'base':'f', 'letters':'\u0066\u24D5\uFF46\u1E1F\u0192\uA77C'},
1689
+ {'base':'g', 'letters':'\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F'},
1690
+ {'base':'h', 'letters':'\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265'},
1691
+ {'base':'hv','letters':'\u0195'},
1692
+ {'base':'i', 'letters':'\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131'},
1693
+ {'base':'j', 'letters':'\u006A\u24D9\uFF4A\u0135\u01F0\u0249'},
1694
+ {'base':'k', 'letters':'\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3'},
1695
+ {'base':'l', 'letters':'\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747'},
1696
+ {'base':'lj','letters':'\u01C9'},
1697
+ {'base':'m', 'letters':'\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F'},
1698
+ {'base':'n', 'letters':'\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5'},
1699
+ {'base':'nj','letters':'\u01CC'},
1700
+ {'base':'o', 'letters':'\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275'},
1701
+ {'base':'oi','letters':'\u01A3'},
1702
+ {'base':'ou','letters':'\u0223'},
1703
+ {'base':'oo','letters':'\uA74F'},
1704
+ {'base':'p','letters':'\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755'},
1705
+ {'base':'q','letters':'\u0071\u24E0\uFF51\u024B\uA757\uA759'},
1706
+ {'base':'r','letters':'\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783'},
1707
+ {'base':'s','letters':'\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B'},
1708
+ {'base':'t','letters':'\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787'},
1709
+ {'base':'tz','letters':'\uA729'},
1710
+ {'base':'u','letters': '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289'},
1711
+ {'base':'v','letters':'\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C'},
1712
+ {'base':'vy','letters':'\uA761'},
1713
+ {'base':'w','letters':'\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73'},
1714
+ {'base':'x','letters':'\u0078\u24E7\uFF58\u1E8B\u1E8D'},
1715
+ {'base':'y','letters':'\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF'},
1716
+ {'base':'z','letters':'\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763'}
1717
+ ];
1718
+
1719
+ var diacriticsMap = {};
1720
+ for (var i = 0; i < defaultDiacriticsRemovalap.length; i++) {
1721
+ var letters = defaultDiacriticsRemovalap[i].letters.split("");
1722
+ for (var j = 0; j < letters.length ; j++){
1723
+ diacriticsMap[letters[j]] = defaultDiacriticsRemovalap[i].base;
1724
+ }
1725
+ }
1726
+
1727
+ // "what?" version ... http://jsperf.com/diacritics/12
1728
+ function removeDiacritics (str) {
1729
+ return str.replace(/[^\u0000-\u007E]/g, function(a){
1730
+ return diacriticsMap[a] || a;
1731
+ });
1732
+ }
1733
+
1734
+ return function (input) {
1735
+
1736
+ return isString(input)
1737
+ ? removeDiacritics(input)
1738
+ : input;
1739
+ }
1740
+ }]);
1741
+
1742
+ /**
1743
+ * @ngdoc filter
1744
+ * @name ltrim
1745
+ * @kind function
1746
+ *
1747
+ * @description
1748
+ * Left trim. Similar to trimFilter, but only for left side.
1749
+ */
1750
+ angular.module('a8m.ltrim', [])
1751
+ .filter('ltrim', function () {
1752
+ return function(input, chars) {
1753
+
1754
+ var trim = chars || '\\s';
1755
+
1756
+ return isString(input)
1757
+ ? input.replace(new RegExp('^' + trim + '+'), '')
1758
+ : input;
1759
+ }
1760
+ });
1761
+
1762
+ /**
1763
+ * @ngdoc filter
1764
+ * @name match
1765
+ * @kind function
1766
+ *
1767
+ * @description
1768
+ * Return the matched pattern in a string.
1769
+ */
1770
+ angular.module('a8m.match', [])
1771
+ .filter('match', function () {
1772
+ return function (input, pattern, flag) {
1773
+
1774
+ var reg = new RegExp(pattern, flag);
1775
+
1776
+ return isString(input)
1777
+ ? input.match(reg)
1778
+ : null;
1779
+ }
1780
+ });
1781
+
1782
+ /**
1783
+ * @ngdoc filter
1784
+ * @name repeat
1785
+ * @kind function
1786
+ *
1787
+ * @description
1788
+ * Repeats a string n times
1789
+ */
1790
+ angular.module('a8m.repeat', [])
1791
+ .filter('repeat',[ function () {
1792
+ return function (input, n, separator) {
1793
+
1794
+ var times = ~~n;
1795
+
1796
+ if(!isString(input)) {
1797
+ return input;
1798
+ }
1799
+
1800
+ return !times
1801
+ ? input
1802
+ : strRepeat(input, --n, separator || '');
1803
+ }
1804
+ }]);
1805
+
1806
+ /**
1807
+ * Repeats a string n times with given separator
1808
+ * @param str string to repeat
1809
+ * @param n number of times
1810
+ * @param sep separator
1811
+ * @returns {*}
1812
+ */
1813
+ function strRepeat(str, n, sep) {
1814
+ if(!n) {
1815
+ return str;
1816
+ }
1817
+ return str + sep + strRepeat(str, --n, sep);
1818
+ }
1819
+ /**
1820
+ * @ngdoc filter
1821
+ * @name rtrim
1822
+ * @kind function
1823
+ *
1824
+ * @description
1825
+ * Right trim. Similar to trimFilter, but only for right side.
1826
+ */
1827
+ angular.module('a8m.rtrim', [])
1828
+ .filter('rtrim', function () {
1829
+ return function(input, chars) {
1830
+
1831
+ var trim = chars || '\\s';
1832
+
1833
+ return isString(input)
1834
+ ? input.replace(new RegExp(trim + '+$'), '')
1835
+ : input;
1836
+ }
1837
+ });
1838
+
1839
+ /**
1840
+ * @ngdoc filter
1841
+ * @name slugify
1842
+ * @kind function
1843
+ *
1844
+ * @description
1845
+ * remove spaces from string, replace with "-" or given argument
1846
+ */
1847
+ angular.module('a8m.slugify', [])
1848
+ .filter('slugify',[ function () {
1849
+ return function (input, sub) {
1850
+
1851
+ var replace = (isUndefined(sub)) ? '-' : sub;
1852
+
1853
+ return isString(input)
1854
+ ? input.toLowerCase().replace(/\s+/g, replace)
1855
+ : input;
1856
+ }
1857
+ }]);
1858
+
1859
+ /**
1860
+ * @ngdoc filter
1861
+ * @name startWith
1862
+ * @kind function
1863
+ *
1864
+ * @description
1865
+ * checks whether string starts with the starts parameter.
1866
+ */
1867
+ angular.module('a8m.starts-with', [])
1868
+ .filter('startsWith', function () {
1869
+ return function (input, start, csensitive) {
1870
+
1871
+ var sensitive = csensitive || false;
1872
+
1873
+ if(!isString(input) || isUndefined(start)) {
1874
+ return input;
1875
+ }
1876
+
1877
+ input = (sensitive) ? input : input.toLowerCase();
1878
+
1879
+ return !input.indexOf((sensitive) ? start : start.toLowerCase());
1880
+ }
1881
+ });
1882
+
1883
+ /**
1884
+ * @ngdoc filter
1885
+ * @name stringular
1886
+ * @kind function
1887
+ *
1888
+ * @description
1889
+ * get string with {n} and replace match with enumeration values
1890
+ */
1891
+ angular.module('a8m.stringular', [])
1892
+ .filter('stringular', function () {
1893
+ return function(input) {
1894
+
1895
+ var args = Array.prototype.slice.call(arguments, 1);
1896
+
1897
+ return input.replace(/{(\d+)}/g, function (match, number) {
1898
+ return isUndefined(args[number]) ? match : args[number];
1899
+ });
1900
+ }
1901
+ });
1902
+
1903
+ /**
1904
+ * @ngdoc filter
1905
+ * @name stripTags
1906
+ * @kind function
1907
+ *
1908
+ * @description
1909
+ * strip html tags from string
1910
+ */
1911
+ angular.module('a8m.strip-tags', [])
1912
+ .filter('stripTags', function () {
1913
+ return function(input) {
1914
+ return isString(input)
1915
+ ? input.replace(/<\S[^><]*>/g, '')
1916
+ : input;
1917
+ }
1918
+ });
1919
+
1920
+ /**
1921
+ * @ngdoc filter
1922
+ * @name test
1923
+ * @kind function
1924
+ *
1925
+ * @description
1926
+ * test if a string match a pattern.
1927
+ */
1928
+ angular.module('a8m.test', [])
1929
+ .filter('test', function () {
1930
+ return function (input, pattern, flag) {
1931
+
1932
+ var reg = new RegExp(pattern, flag);
1933
+
1934
+ return isString(input)
1935
+ ? reg.test(input)
1936
+ : input;
1937
+ }
1938
+ });
1939
+
1940
+ /**
1941
+ * @ngdoc filter
1942
+ * @name trim
1943
+ * @kind function
1944
+ *
1945
+ * @description
1946
+ * Strip whitespace (or other characters) from the beginning and end of a string
1947
+ */
1948
+ angular.module('a8m.trim', [])
1949
+ .filter('trim', function () {
1950
+ return function(input, chars) {
1951
+
1952
+ var trim = chars || '\\s';
1953
+
1954
+ return isString(input)
1955
+ ? input.replace(new RegExp('^' + trim + '+|' + trim + '+$', 'g'), '')
1956
+ : input;
1957
+ }
1958
+ });
1959
+
1960
+ /**
1961
+ * @ngdoc filter
1962
+ * @name truncate
1963
+ * @kind function
1964
+ *
1965
+ * @description
1966
+ * truncates a string given a specified length, providing a custom string to denote an omission.
1967
+ */
1968
+ angular.module('a8m.truncate', [])
1969
+ .filter('truncate', function () {
1970
+ return function(input, length, suffix, preserve) {
1971
+
1972
+ length = isUndefined(length) ? input.length : length;
1973
+ preserve = preserve || false;
1974
+ suffix = suffix || '';
1975
+
1976
+ if(!isString(input) || (input.length <= length)) return input;
1977
+
1978
+ return input.substring(0, (preserve)
1979
+ ? ((input.indexOf(' ', length) === -1) ? input.length : input.indexOf(' ', length))
1980
+ : length) + suffix;
1981
+ };
1982
+ });
1983
+
1984
+ /**
1985
+ * @ngdoc filter
1986
+ * @name ucfirst
1987
+ * @kind function
1988
+ *
1989
+ * @description
1990
+ * ucfirst
1991
+ */
1992
+ angular.module('a8m.ucfirst', [])
1993
+ .filter('ucfirst', [function() {
1994
+ return function(input) {
1995
+ return isString(input)
1996
+ ? input
1997
+ .split(' ')
1998
+ .map(function (ch) {
1999
+ return ch.charAt(0).toUpperCase() + ch.substring(1);
2000
+ })
2001
+ .join(' ')
2002
+ : input;
2003
+ }
2004
+ }]);
2005
+
2006
+ /**
2007
+ * @ngdoc filter
2008
+ * @name uriComponentEncode
2009
+ * @kind function
2010
+ *
2011
+ * @description
2012
+ * get string as parameter and return encoded string
2013
+ */
2014
+ angular.module('a8m.uri-component-encode', [])
2015
+ .filter('uriComponentEncode',['$window', function ($window) {
2016
+ return function (input) {
2017
+ return isString(input)
2018
+ ? $window.encodeURIComponent(input)
2019
+ : input;
2020
+ }
2021
+ }]);
2022
+
2023
+ /**
2024
+ * @ngdoc filter
2025
+ * @name uriEncode
2026
+ * @kind function
2027
+ *
2028
+ * @description
2029
+ * get string as parameter and return encoded string
2030
+ */
2031
+ angular.module('a8m.uri-encode', [])
2032
+ .filter('uriEncode',['$window', function ($window) {
2033
+ return function (input) {
2034
+ return isString(input)
2035
+ ? $window.encodeURI(input)
2036
+ : input;
2037
+ }
2038
+ }]);
2039
+
2040
+ /**
2041
+ * @ngdoc filter
2042
+ * @name wrap
2043
+ * @kind function
2044
+ *
2045
+ * @description
2046
+ * Wrap a string with another string
2047
+ */
2048
+ angular.module('a8m.wrap', [])
2049
+ .filter('wrap', function () {
2050
+ return function(input, wrap, ends) {
2051
+ return isString(input) && isDefined(wrap)
2052
+ ? [wrap, input, ends || wrap].join('')
2053
+ : input;
2054
+ }
2055
+ });
2056
+
2057
+ /**
2058
+ * @ngdoc provider
2059
+ * @name filterWatcher
2060
+ * @kind function
2061
+ *
2062
+ * @description
2063
+ * store specific filters result in $$cache, based on scope life time(avoid memory leak).
2064
+ * on scope.$destroy remove it's cache from $$cache container
2065
+ */
2066
+
2067
+ angular.module('a8m.filter-watcher', [])
2068
+ .provider('filterWatcher', function() {
2069
+
2070
+ this.$get = ['$window', '$rootScope', function($window, $rootScope) {
2071
+
2072
+ /**
2073
+ * Cache storing
2074
+ * @type {Object}
2075
+ */
2076
+ var $$cache = {};
2077
+
2078
+ /**
2079
+ * Scope listeners container
2080
+ * scope.$destroy => remove all cache keys
2081
+ * bind to current scope.
2082
+ * @type {Object}
2083
+ */
2084
+ var $$listeners = {};
2085
+
2086
+ /**
2087
+ * $timeout without triggering the digest cycle
2088
+ * @type {function}
2089
+ */
2090
+ var $$timeout = $window.setTimeout;
2091
+
2092
+ /**
2093
+ * @description
2094
+ * get `HashKey` string based on the given arguments.
2095
+ * @param fName
2096
+ * @param args
2097
+ * @returns {string}
2098
+ */
2099
+ function getHashKey(fName, args) {
2100
+ return [fName, angular.toJson(args)]
2101
+ .join('#')
2102
+ .replace(/"/g,'');
2103
+ }
2104
+
2105
+ /**
2106
+ * @description
2107
+ * fir on $scope.$destroy,
2108
+ * remove cache based scope from `$$cache`,
2109
+ * and remove itself from `$$listeners`
2110
+ * @param event
2111
+ */
2112
+ function removeCache(event) {
2113
+ var id = event.targetScope.$id;
2114
+ forEach($$listeners[id], function(key) {
2115
+ delete $$cache[key];
2116
+ });
2117
+ delete $$listeners[id];
2118
+ }
2119
+
2120
+ /**
2121
+ * @description
2122
+ * for angular version that greater than v.1.3.0
2123
+ * it clear cache when the digest cycle is end.
2124
+ */
2125
+ function cleanStateless() {
2126
+ $$timeout(function() {
2127
+ if(!$rootScope.$$phase)
2128
+ $$cache = {};
2129
+ });
2130
+ }
2131
+
2132
+ /**
2133
+ * @description
2134
+ * Store hashKeys in $$listeners container
2135
+ * on scope.$destroy, remove them all(bind an event).
2136
+ * @param scope
2137
+ * @param hashKey
2138
+ * @returns {*}
2139
+ */
2140
+ function addListener(scope, hashKey) {
2141
+ var id = scope.$id;
2142
+ if(isUndefined($$listeners[id])) {
2143
+ scope.$on('$destroy', removeCache);
2144
+ $$listeners[id] = [];
2145
+ }
2146
+ return $$listeners[id].push(hashKey);
2147
+ }
2148
+
2149
+ /**
2150
+ * @description
2151
+ * return the `cacheKey` or undefined.
2152
+ * @param filterName
2153
+ * @param args
2154
+ * @returns {*}
2155
+ */
2156
+ function $$isMemoized(filterName, args) {
2157
+ var hashKey = getHashKey(filterName, args);
2158
+ return $$cache[hashKey];
2159
+ }
2160
+
2161
+ /**
2162
+ * @description
2163
+ * store `result` in `$$cache` container, based on the hashKey.
2164
+ * add $destroy listener and return result
2165
+ * @param filterName
2166
+ * @param args
2167
+ * @param scope
2168
+ * @param result
2169
+ * @returns {*}
2170
+ */
2171
+ function $$memoize(filterName, args, scope, result) {
2172
+ var hashKey = getHashKey(filterName, args);
2173
+ //store result in `$$cache` container
2174
+ $$cache[hashKey] = result;
2175
+ // for angular versions that less than 1.3
2176
+ // add to `$destroy` listener, a cleaner callback
2177
+ if(isScope(scope)) {
2178
+ addListener(scope, hashKey);
2179
+ } else {
2180
+ cleanStateless();
2181
+ }
2182
+ return result;
2183
+ }
2184
+
2185
+ return {
2186
+ isMemoized: $$isMemoized,
2187
+ memoize: $$memoize
2188
+ }
2189
+
2190
+ }];
2191
+ });
2192
+
2193
+
2194
+ /**
2195
+ * @ngdoc module
2196
+ * @name angular.filters
2197
+ * @description
2198
+ * Bunch of useful filters for angularJS
2199
+ */
2200
+
2201
+ angular.module('angular.filter', [
2202
+
2203
+ 'a8m.ucfirst',
2204
+ 'a8m.uri-encode',
2205
+ 'a8m.uri-component-encode',
2206
+ 'a8m.slugify',
2207
+ 'a8m.latinize',
2208
+ 'a8m.strip-tags',
2209
+ 'a8m.stringular',
2210
+ 'a8m.truncate',
2211
+ 'a8m.starts-with',
2212
+ 'a8m.ends-with',
2213
+ 'a8m.wrap',
2214
+ 'a8m.trim',
2215
+ 'a8m.ltrim',
2216
+ 'a8m.rtrim',
2217
+ 'a8m.repeat',
2218
+ 'a8m.test',
2219
+ 'a8m.match',
2220
+
2221
+ 'a8m.to-array',
2222
+ 'a8m.concat',
2223
+ 'a8m.contains',
2224
+ 'a8m.unique',
2225
+ 'a8m.is-empty',
2226
+ 'a8m.after',
2227
+ 'a8m.after-where',
2228
+ 'a8m.before',
2229
+ 'a8m.before-where',
2230
+ 'a8m.defaults',
2231
+ 'a8m.where',
2232
+ 'a8m.reverse',
2233
+ 'a8m.remove',
2234
+ 'a8m.remove-with',
2235
+ 'a8m.group-by',
2236
+ 'a8m.count-by',
2237
+ 'a8m.chunk-by',
2238
+ 'a8m.search-field',
2239
+ 'a8m.fuzzy-by',
2240
+ 'a8m.fuzzy',
2241
+ 'a8m.omit',
2242
+ 'a8m.pick',
2243
+ 'a8m.every',
2244
+ 'a8m.filter-by',
2245
+ 'a8m.xor',
2246
+ 'a8m.map',
2247
+ 'a8m.first',
2248
+ 'a8m.last',
2249
+ 'a8m.flatten',
2250
+ 'a8m.join',
2251
+ 'a8m.range',
2252
+
2253
+ 'a8m.math',
2254
+ 'a8m.math.max',
2255
+ 'a8m.math.min',
2256
+ 'a8m.math.percent',
2257
+ 'a8m.math.radix',
2258
+ 'a8m.math.sum',
2259
+ 'a8m.math.degrees',
2260
+ 'a8m.math.radians',
2261
+ 'a8m.math.byteFmt',
2262
+ 'a8m.math.kbFmt',
2263
+ 'a8m.math.shortFmt',
2264
+
2265
+ 'a8m.angular',
2266
+ 'a8m.conditions',
2267
+ 'a8m.is-null',
2268
+
2269
+ 'a8m.filter-watcher'
2270
+ ]);
2271
+ })( window, window.angular );