gina 0.1.1-alpha.16 → 0.1.1-alpha.160

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 (324) hide show
  1. package/AUTHORS +2 -1
  2. package/LICENSE +1 -1
  3. package/README-4Contributors.md +30 -0
  4. package/README.md +202 -32
  5. package/bin/cli +165 -68
  6. package/bin/cli-debug +49 -18
  7. package/bin/cmd +40 -18
  8. package/bin/gina +48 -37
  9. package/{framework/v0.1.1-alpha.16/core/template/command/gina.bat.tpl → bin/gina.bat} +0 -0
  10. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/AUTHORS +0 -0
  11. package/framework/{v0.1.1-alpha.16/lib/inherits → v0.1.1-alpha.160}/LICENSE +1 -1
  12. package/framework/v0.1.1-alpha.160/VERSION +1 -0
  13. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/asset/html/nolayout.html +0 -0
  14. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/asset/html/static.html +0 -0
  15. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/asset/img/android-chrome-192x192.png +0 -0
  16. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/asset/img/android-chrome-512x512.png +0 -0
  17. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/asset/img/apple-touch-icon.png +0 -0
  18. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/asset/img/favicon-16x16.png +0 -0
  19. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/asset/img/favicon-32x32.png +0 -0
  20. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/asset/img/favicon.ico +0 -0
  21. package/framework/{v0.1.1-alpha.16/core/asset/js → v0.1.1-alpha.160/core/asset}/plugin/dist/gina.js +887 -874
  22. package/framework/{v0.1.1-alpha.16/core/asset/js → v0.1.1-alpha.160/core/asset}/plugin/dist/gina.js.map +3 -3
  23. package/framework/{v0.1.1-alpha.16/core/asset/js → v0.1.1-alpha.160/core/asset}/plugin/dist/gina.min.css +0 -0
  24. package/framework/{v0.1.1-alpha.16/core/asset/js → v0.1.1-alpha.160/core/asset}/plugin/dist/gina.min.css.map +0 -0
  25. package/framework/v0.1.1-alpha.160/core/asset/plugin/dist/gina.min.js +739 -0
  26. package/framework/v0.1.1-alpha.160/core/asset/plugin/dist/gina.min.js.map +8 -0
  27. package/framework/{v0.1.1-alpha.16/core/asset/js → v0.1.1-alpha.160/core/asset}/plugin/dist/gina.onload.min.js +0 -0
  28. package/framework/{v0.1.1-alpha.16/core/asset/js → v0.1.1-alpha.160/core/asset}/plugin/dist/gina.onload.min.js.map +0 -0
  29. package/framework/v0.1.1-alpha.160/core/asset/plugin/dist/toolbar/css/toolbar-min.css +1 -0
  30. package/framework/v0.1.1-alpha.160/core/asset/plugin/dist/toolbar/css/toolbar.css +3 -0
  31. package/framework/v0.1.1-alpha.160/core/asset/plugin/dist/toolbar/css/toolbar.css.map +1 -0
  32. package/framework/v0.1.1-alpha.160/core/asset/plugin/dist/toolbar/js/jquery-3.1.0.min.js +4 -0
  33. package/framework/v0.1.1-alpha.160/core/asset/plugin/dist/toolbar/main.js +1542 -0
  34. package/framework/v0.1.1-alpha.160/core/asset/plugin/dist/toolbar/toolbar.html +251 -0
  35. package/framework/{v0.1.1-alpha.16/core/asset/js → v0.1.1-alpha.160/core/asset}/plugin/readme.md +6 -6
  36. package/framework/{v0.1.1-alpha.16/core/asset/js → v0.1.1-alpha.160/core/asset}/plugin/uuid.json +0 -0
  37. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/config.js +29 -14
  38. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/connectors/couchbase/index.js +331 -222
  39. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/connectors/couchbase/lib/connector.js +6 -4
  40. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/connectors/couchbase/lib/connector.v2.js +47 -47
  41. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/connectors/couchbase/lib/connector.v3.js +0 -0
  42. package/framework/v0.1.1-alpha.160/core/connectors/couchbase/lib/connector.v4.js +384 -0
  43. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/connectors/couchbase/lib/n1ql.js +3 -2
  44. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/connectors/couchbase/lib/session-store.js +6 -5
  45. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/connectors/couchbase/lib/session-store.v2.js +0 -0
  46. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/connectors/couchbase/lib/session-store.v3.js +0 -0
  47. package/framework/v0.1.1-alpha.160/core/connectors/couchbase/lib/session-store.v4.js +362 -0
  48. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/controller/controller.framework.js +0 -0
  49. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/controller/controller.js +691 -677
  50. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/controller/index.js +0 -0
  51. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/busboy/.travis.yml +0 -0
  52. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/busboy/LICENSE +0 -0
  53. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/busboy/README.md +0 -0
  54. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/busboy/deps/encoding/encoding-indexes.js +0 -0
  55. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/busboy/deps/encoding/encoding.js +0 -0
  56. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/busboy/lib/main.js +0 -0
  57. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/busboy/lib/types/multipart.js +0 -0
  58. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/busboy/lib/types/urlencoded.js +0 -0
  59. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/busboy/lib/utils.js +0 -0
  60. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/busboy/package.json +0 -0
  61. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/deps/swig-client/swig-2.0.0.min.js +0 -0
  62. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/dev/index.js +1 -1
  63. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/dev/lib/class.js +0 -0
  64. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/dev/lib/factory.js +1 -1
  65. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/dev/lib/tools.js +0 -0
  66. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/gna.js +3 -4
  67. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/README.md +0 -0
  68. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/currency.json +0 -0
  69. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/dist/language/en.json +0 -0
  70. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/dist/language/fr.json +0 -0
  71. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/dist/region/en.json +0 -0
  72. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/dist/region/fr.json +0 -0
  73. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/index.js +2 -2
  74. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/src/make.js +0 -0
  75. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/src/resources/currency.csv +0 -0
  76. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/src/resources/region.csv +0 -0
  77. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/locales/src/resources/region.mapping.json +0 -0
  78. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/mime.types +0 -0
  79. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/model/entity.js +81 -61
  80. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/model/index.js +8 -7
  81. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/model/template/entityFactory.js +1 -1
  82. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/model/template/index.js +1 -1
  83. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/README.md +0 -0
  84. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/index.js +1 -1
  85. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/file/README.md +0 -0
  86. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/file/build.json +0 -0
  87. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/file/package.json +1 -1
  88. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/intl/README.md +0 -0
  89. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/intl/build.json +0 -0
  90. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/intl/package.json +1 -1
  91. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/intl/src/main.js +0 -0
  92. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/storage/README.md +0 -0
  93. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/storage/build.json +0 -0
  94. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/storage/package.json +1 -1
  95. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/storage/src/main.js +0 -0
  96. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/validator/README.md +0 -0
  97. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/validator/build.json +0 -0
  98. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/validator/package.json +1 -1
  99. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/validator/src/form-validator.js +0 -0
  100. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/plugins/lib/validator/src/main.js +0 -0
  101. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/router.js +92 -79
  102. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/server.express.js +0 -0
  103. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/server.isaac.js +117 -108
  104. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/server.js +44 -1
  105. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/status.codes +0 -0
  106. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle/config/app.json +0 -0
  107. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle/config/routing.json +0 -0
  108. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle/config/settings.json +0 -0
  109. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle/config/settings.server.json +0 -0
  110. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle/config/templates.json +4 -4
  111. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle/controllers/controller.content.js +0 -0
  112. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle/controllers/controller.js +0 -0
  113. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle/controllers/setup.js +0 -0
  114. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle/index.js +0 -0
  115. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle_namespace/controllers/controller.js +0 -0
  116. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle_public/css/default.css +0 -0
  117. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle_public/css/vendor/readme.md +0 -0
  118. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle_public/favicon.ico +0 -0
  119. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle_public/js/vendor/readme.md +0 -0
  120. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle_public/readme.md +0 -0
  121. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/boilerplate/bundle_templates/handlers/main.js +0 -0
  122. package/framework/v0.1.1-alpha.160/core/template/boilerplate/bundle_templates/html/content/homepage.html +8 -0
  123. package/framework/v0.1.1-alpha.160/core/template/boilerplate/bundle_templates/html/includes/error-msg-noscript.html +11 -0
  124. package/framework/v0.1.1-alpha.160/core/template/boilerplate/bundle_templates/html/includes/error-msg-outdated-browser.html +8 -0
  125. package/framework/{v0.1.1-alpha.16/core/template/boilerplate/bundle_templates/html/layout → v0.1.1-alpha.160/core/template/boilerplate/bundle_templates/html/layouts}/main.html +10 -3
  126. package/framework/v0.1.1-alpha.160/core/template/command/gina.bat.tpl +8 -0
  127. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/command/gina.tpl +1 -1
  128. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/conf/env.json +0 -0
  129. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/conf/manifest.json +0 -0
  130. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/conf/package.json +1 -1
  131. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/conf/settings.json +0 -0
  132. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/conf/statics.json +3 -3
  133. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/conf/templates.json +2 -2
  134. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/error/client/json/401.json +0 -0
  135. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/error/client/json/403.json +0 -0
  136. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/error/client/json/404.json +0 -0
  137. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/error/server/html/50x.html +0 -0
  138. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/error/server/json/500.json +0 -0
  139. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/error/server/json/503.json +0 -0
  140. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/core/template/extensions/logger/config.json +0 -0
  141. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/console.js +1 -1
  142. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/context.js +145 -5
  143. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/dateFormat.js +4 -2
  144. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/index.js +10 -5
  145. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/json/README.md +0 -0
  146. package/framework/{v0.1.1-alpha.16/helpers/plugins → v0.1.1-alpha.160/helpers/json}/package.json +1 -1
  147. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/json/src/main.js +22 -22
  148. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/path.js +143 -89
  149. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/plugins/README.md +0 -0
  150. package/framework/{v0.1.1-alpha.16/helpers/json → v0.1.1-alpha.160/helpers/plugins}/package.json +1 -1
  151. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/plugins/src/api-error.js +23 -23
  152. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/plugins/src/main.js +2 -2
  153. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/prototypes.js +35 -36
  154. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/task.js +21 -14
  155. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/helpers/text.js +1 -1
  156. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/archiver/README.md +0 -0
  157. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/archiver/build.json +0 -0
  158. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/archiver/package.json +1 -1
  159. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/archiver/src/dep/jszip.min.js +0 -0
  160. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/archiver/src/main.js +167 -167
  161. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/aliases.json +4 -1
  162. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/add.js +43 -17
  163. package/framework/v0.1.1-alpha.160/lib/cmd/bundle/arguments.json +6 -0
  164. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/copy.js +0 -0
  165. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/cp.js +0 -0
  166. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/help.js +0 -0
  167. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/help.txt +2 -2
  168. package/framework/v0.1.1-alpha.160/lib/cmd/bundle/list.js +176 -0
  169. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/remove.js +22 -22
  170. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/rename.js +0 -0
  171. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/restart.js +0 -0
  172. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/rm.js +0 -0
  173. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/start.js +257 -46
  174. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/status.js +0 -0
  175. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/bundle/stop.js +93 -74
  176. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/env/add.js +0 -0
  177. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/env/get.js +0 -0
  178. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/env/help.js +0 -0
  179. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/env/help.txt +0 -0
  180. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/env/link-dev.js +0 -0
  181. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/env/list.js +0 -0
  182. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/env/remove.js +0 -0
  183. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/env/rm.js +0 -0
  184. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/env/set.js +0 -0
  185. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/env/unset.js +0 -0
  186. package/framework/{v0.1.1-alpha.16/lib/cmd/scope → v0.1.1-alpha.160/lib/cmd/env}/use.js +21 -1
  187. package/framework/v0.1.1-alpha.160/lib/cmd/framework/build.js +85 -0
  188. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/dot.js +0 -0
  189. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/get.js +0 -0
  190. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/help.js +0 -0
  191. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/help.txt +0 -0
  192. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/init.js +212 -21
  193. package/framework/v0.1.1-alpha.160/lib/cmd/framework/link-node-modules.js +86 -0
  194. package/framework/v0.1.1-alpha.160/lib/cmd/framework/link.js +94 -0
  195. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/msg.json +0 -0
  196. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/open.js +15 -0
  197. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/restart.js +58 -26
  198. package/framework/v0.1.1-alpha.160/lib/cmd/framework/set.js +264 -0
  199. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/start.js +35 -12
  200. package/framework/v0.1.1-alpha.160/lib/cmd/framework/status.js +138 -0
  201. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/stop.js +44 -28
  202. package/framework/v0.1.1-alpha.160/lib/cmd/framework/tail.js +271 -0
  203. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/update.js +0 -0
  204. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/framework/version.js +12 -3
  205. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/gina-dev.1.md +0 -0
  206. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/gina-framework.1.md +0 -0
  207. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/gina.1.md +0 -0
  208. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/helper.js +74 -5
  209. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/index.js +22 -22
  210. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/msg.json +0 -0
  211. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/port/help.js +0 -0
  212. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/port/help.txt +0 -0
  213. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/port/inc/scan.js +32 -17
  214. package/framework/v0.1.1-alpha.160/lib/cmd/port/list.js +446 -0
  215. package/framework/v0.1.1-alpha.160/lib/cmd/port/reset.js +426 -0
  216. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/port/set.js +0 -0
  217. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/add.js +146 -122
  218. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/arguments.json +0 -0
  219. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/build.js +0 -0
  220. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/help.js +0 -0
  221. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/help.txt +0 -0
  222. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/import.js +0 -0
  223. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/list.js +16 -2
  224. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/move.js +0 -0
  225. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/remove.js +17 -17
  226. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/rename.js +0 -0
  227. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/restart.js +0 -0
  228. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/rm.js +0 -0
  229. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/start.js +0 -0
  230. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/status.js +0 -0
  231. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/project/stop.js +0 -0
  232. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/protocol/help.js +0 -0
  233. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/protocol/help.txt +0 -0
  234. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/protocol/list.js +0 -0
  235. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/protocol/set.js +239 -201
  236. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/scope/help.js +0 -0
  237. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/scope/help.txt +0 -0
  238. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/scope/link-local.js +0 -0
  239. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/scope/list.js +0 -0
  240. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/scope/remove.js +0 -0
  241. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/scope/rm.js +0 -0
  242. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/scope/set.js +0 -0
  243. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/scope/unset.js +0 -0
  244. package/framework/{v0.1.1-alpha.16/lib/cmd/env → v0.1.1-alpha.160/lib/cmd/scope}/use.js +0 -0
  245. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cmd/view/add.js +34 -9
  246. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/collection/README.md +0 -0
  247. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/collection/build.json +0 -0
  248. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/collection/package.json +1 -1
  249. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/collection/src/main.js +0 -0
  250. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/config.js +2 -1
  251. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cron/README.md +0 -0
  252. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cron/package.json +1 -1
  253. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/cron/src/main.js +0 -0
  254. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/generator/index.js +1 -1
  255. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/index.js +1 -1
  256. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160/lib/inherits}/LICENSE +1 -1
  257. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/inherits/README.md +0 -0
  258. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/inherits/example/inheriting_eventemitter.js +0 -0
  259. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/inherits/example/protected_inheritance.js +0 -0
  260. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/inherits/example/simple_inheritance.js +0 -0
  261. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/inherits/example/super_attribute_overridden_by_child_on_init.js +0 -0
  262. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/inherits/package.json +1 -1
  263. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/inherits/src/main.js +1 -1
  264. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/README.md +0 -0
  265. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/package.json +1 -1
  266. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/src/containers/default/index.js +13 -2
  267. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/src/containers/file/index.js +105 -14
  268. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/src/containers/file/lib/logrotator/README.md +0 -0
  269. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/src/containers/file/lib/logrotator/index.js +0 -0
  270. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/src/containers/mq/index.js +2 -1
  271. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/src/containers/mq/listener.js +16 -14
  272. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/src/containers/mq/speaker.js +32 -3
  273. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/src/helper.js +20 -1
  274. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/logger/src/main.js +5 -2
  275. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/math/index.js +7 -7
  276. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/merge/README.md +0 -0
  277. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/merge/example/merge.js +0 -0
  278. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/merge/example/merge_2_literal objects.js +0 -0
  279. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/merge/example/merge_and_preserve_first.js +0 -0
  280. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/merge/package.json +1 -1
  281. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/merge/src/main.js +0 -0
  282. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/model.js +9 -9
  283. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/proc.js +75 -47
  284. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/routing/README.md +0 -0
  285. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/routing/build.json +0 -0
  286. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/routing/package.json +1 -1
  287. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/routing/src/main.js +258 -258
  288. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/session-store.js +6 -6
  289. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/shell.js +3 -3
  290. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/swig-filters/README.md +0 -0
  291. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/swig-filters/package.json +1 -1
  292. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/swig-filters/src/main.js +55 -52
  293. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/url/README.md +0 -0
  294. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/url/index.js +0 -0
  295. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/url/mocks.json +0 -0
  296. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/url/routing.json +0 -0
  297. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/url/test.js +0 -0
  298. package/framework/{v0.1.1-alpha.16 → v0.1.1-alpha.160}/lib/validator.js +0 -0
  299. package/framework/v0.1.1-alpha.160/package.json +14 -0
  300. package/package.json +33 -24
  301. package/resources/home/main.json +44 -1
  302. package/resources/home/settings.json +7 -0
  303. package/resources/home/user/extensions/logger/default/config.json +1 -1
  304. package/resources/package.json.template +29 -18
  305. package/script/post_install.js +410 -120
  306. package/script/post_publish.js +185 -0
  307. package/script/pre_install.js +424 -76
  308. package/script/prepare_version.js +152 -22
  309. package/utils/helper.js +230 -185
  310. package/utils/prototypes.js +9 -9
  311. package/utils/prototypes.json_clone.js +31 -31
  312. package/doc/framework/cli/doc.json +0 -9
  313. package/doc/framework/index.md +0 -60
  314. package/framework/v0.1.1-alpha.16/VERSION +0 -1
  315. package/framework/v0.1.1-alpha.16/core/asset/js/plugin/dist/gina.min.js +0 -736
  316. package/framework/v0.1.1-alpha.16/core/asset/js/plugin/dist/gina.min.js.map +0 -56
  317. package/framework/v0.1.1-alpha.16/core/template/boilerplate/bundle_templates/html/homepage.html +0 -4
  318. package/framework/v0.1.1-alpha.16/lib/cmd/bundle/arguments.json +0 -4
  319. package/framework/v0.1.1-alpha.16/lib/cmd/bundle/list.js +0 -129
  320. package/framework/v0.1.1-alpha.16/lib/cmd/framework/set.js +0 -161
  321. package/framework/v0.1.1-alpha.16/lib/cmd/framework/status.js +0 -72
  322. package/framework/v0.1.1-alpha.16/lib/cmd/framework/tail.js +0 -183
  323. package/framework/v0.1.1-alpha.16/lib/cmd/port/list.js +0 -176
  324. package/framework/v0.1.1-alpha.16/package.json +0 -14
@@ -34,11 +34,11 @@
34
34
  "'use strict';\nfunction Merge() {\n\n var newTarget = []\n //, keyComparison = 'id' // use for collections merging [{ id: 'val1' }, { id: 'val2' }, {id: 'val3' }, ...]\n ;\n \n \n /**\n *\n * @param {object} target - Target object\n * @param {object} source - Source object\n * @param {boolean} [override] - Override when copying\n *\n * @return {object} [result]\n * */\n var browse = function (target, source) {\n \n if ( typeof(target) == 'undefined' ) {\n target = ( typeof(source) != 'undefined' && Array.isArray(source)) ? [] : {}\n }\n\n var override = false;\n if (( typeof(arguments[arguments.length-1]) == 'boolean' )) {\n override = arguments[arguments.length-1]\n }\n\n var i = 1;\n var length = arguments.length;\n\n var options, /**name,*/ src, copy, copyIsArray, clone;\n\n\n\n // Handle case when target is a string or something (possible in deep copy)\n if (typeof(target) !== 'object' && typeof(target) !== 'function') {\n if (override) {\n if (typeof(arguments[2]) == 'undefined') {\n target = arguments[1]\n } else {\n target = arguments[2]\n }\n } else {\n if (typeof(arguments[0]) == 'undefined') {\n target = arguments[1]\n } else {\n target = arguments[0]\n }\n }\n\n } else {\n for (; i < length; ++i) {\n // Only deal with non-null/undefined values\n if ( typeof(arguments[i]) != 'boolean' && ( options = arguments[i]) != null) {\n if ( typeof(options) != 'object') {\n target = options;\n break;\n }\n\n // both target & options are arrays\n if ( Array.isArray(options) && Array.isArray(target) ) {\n target = mergeArray(options, target, override);\n } else {\n // Merge the base object\n for (var name in options) {\n if (!target) {\n target = { name: null }\n }\n \n src = target[ name ];\n copy = options[ name ];\n\n\n // Prevent never-ending loop\n if (target === copy) {\n continue\n }\n\n // Recurse if we're merging plain objects or arrays\n if (\n copy\n && (\n isObject(copy) ||\n ( copyIsArray = Array.isArray(copy) )\n )\n ) {\n\n var createMode = false;\n if (copyIsArray) {\n copyIsArray = false;\n //clone = src && Array.isArray(src) ? src : [];\n if ( src && Array.isArray(src) ) {\n clone = src || []\n } else if ( isObject(src) ) {\n clone = src || {};\n target[ name ] = clone;\n continue\n } else {\n clone = []\n }\n\n newTarget = clone;\n clone = mergeArray(copy, clone, override);\n target[ name ] = clone;\n continue\n\n } else {\n\n clone = src && isObject(src) ? src : null;\n\n if (!clone) {\n createMode = true;\n clone = {};\n // copy props\n for (var prop in copy) {\n clone[prop] = copy[prop]\n }\n }\n }\n\n\n\n //[propose] Supposed to go deep... deep... deep...\n if ( !override ) {\n // add those in copy not in clone (target)\n\n for (var prop in copy) {\n if (typeof(clone[ prop ]) == 'undefined') {\n if ( Array.isArray(copy[ prop ]) && Array.isArray(clone[ prop ]) ) {\n clone[ prop ] = mergeArray(copy[ prop ], clone[ prop ], override);\n } else {\n clone[ prop ] = copy[ prop ] // don't override existing\n }\n } else if ( Array.isArray(copy[ prop ]) && Array.isArray(clone[ prop ]) ) {\n clone[ prop ] = mergeArray(copy[ prop ], clone[ prop ], override);\n }\n }\n\n\n\n\n // Never move original objects, clone them\n if (typeof(src) != 'boolean' && !createMode ) {//if property is not boolean\n\n // Attention: might lead to a `Maximum call stack size exceeded` Error message\n target[ name ] = browse(clone, copy, override);\n\n // this does not work ... target is returned before the end of process.nextTick !!!\n // process.nextTick(function onBrowse() {\n // target[name] = browse(clone, copy, override)\n // });\n\n // nextTickCalled = true;\n // process.nextTick(function onBrowse() {\n // nextTickCalled = false;\n // //target[ name ] = browse(clone, copy, override);\n // return browse(clone, copy, override);\n // });\n\n\n } else if (createMode) {\n target[ name ] = clone;\n }\n\n } else {\n\n for (var prop in copy) {\n if ( typeof(copy[ prop ]) != 'undefined' ) {\n //clone[prop] = copy[prop]\n if ( Array.isArray(copy[ prop ]) && Array.isArray(clone[ prop ]) ) {\n clone[ prop ] = mergeArray(copy[ prop ], clone[ prop ], override);\n } else {\n clone[ prop ] = copy[ prop ] // don't override existing\n }\n } else if ( Array.isArray(copy[ prop ]) && Array.isArray(clone[ prop ]) ) {\n clone[ prop ] = mergeArray(copy[ prop ], clone[ prop ], override);\n }\n }\n\n target[ name ] = clone;\n }\n\n } else if (copy !== undefined) {\n //[propose]Don't override existing if prop defined or override @ false\n if (\n typeof(src) != 'undefined'\n && src != null\n && src !== copy && !override\n ) {\n target[ name ] = src;\n } else {\n target[ name ] = copy;\n }\n\n }\n }\n }\n }\n\n }\n\n }\n\n newTarget = [];\n \n \n \n // return { \n // 'setKeyComparison' : function(key) {\n // mergeArray.key = key;\n // return target;\n // }\n // } || target\n \n return target;\n\n };\n\n // Will not merge functions items: this is normal\n // Merging arrays is OK, but merging collections is still experimental \n var mergeArray = function(options, target, override) {\n newTarget = [];\n \n \n var newTargetIds = []\n , keyComparison = browse.getKeyComparison()\n , a = null\n , aLen = null\n , i = 0\n ;\n\n if (/^true$/i.test(override)) {\n // if collection, comparison will be done uppon the `id` attribute by default unless you call .setKeyComparison('someField')\n if (\n typeof(options[0]) == 'object'\n && typeof(options[0][keyComparison]) != 'undefined'\n && typeof(target[0]) == 'object' \n && typeof(target[0][keyComparison]) != 'undefined'\n ) {\n\n newTarget = (Array.isArray(target)) ? Array.from(target) : JSON.clone(target);\n for (var nt = 0, ntLen = newTarget.length; nt < ntLen; ++nt) {\n newTargetIds.push(newTarget[nt][keyComparison]);\n }\n \n var _options = JSON.clone(options); \n var index = 0;\n a = 0;\n aLen = _options.length;\n for (var n = next || 0, nLen = target.length; n < nLen; ++n) {\n \n // if (newTargetIds.indexOf(target[n][keyComparison]) == -1) {\n // newTargetIds.push(target[n][keyComparison]);\n \n // //newTarget.push(target[n]);\n // //++index;\n // }\n \n label:\n for (a = a || 0; a < aLen; ++a) {\n \n if (_options[a][keyComparison] === target[n][keyComparison] ) {\n\n if (newTargetIds.indexOf(_options[a][keyComparison]) > -1) {\n \n newTarget[index] = _options[a];\n ++index;\n \n } else if (newTargetIds.indexOf(_options[a][keyComparison]) == -1) {\n\n newTargetIds.push(_options[a][keyComparison]); \n //newTarget.push(_options[a]);\n newTarget[index] = _options[a];\n ++index;\n }\n\n break label;\n \n } else if (newTargetIds.indexOf(_options[a][keyComparison]) == -1) { \n \n newTargetIds.push(_options[a][keyComparison]);\n newTarget.push(_options[a]);\n }\n } // EO For\n }\n\n newTargetIds = [];\n\n return newTarget;\n\n } else { // normal case `arrays` or merging from a blank collection\n if (\n Array.isArray(options) && options.length == 0\n ||\n typeof(options) == 'undefined'\n ) {\n // means that we are trying to replace with an empty array/collection\n // this does not make any sense, so we just return the target as if the merge had no effect\n // DO NOT CHANGE THIS, it affects gina merging config\n return target;\n }\n return options;\n }\n }\n\n if ( options.length == 0 && target.length > 0 ) {\n newTarget = target;\n return newTarget;\n }\n\n if ( target.length == 0 && options.length > 0) {\n a = 0;\n for (; a < options.length; ++a ) {\n target.push(options[a]);\n }\n }\n\n if (newTarget.length == 0 && target.length > 0) { \n // ok, but don't merge objects\n a = 0;\n for (; a < target.length; ++a ) {\n if ( typeof(target[a]) != 'object' && newTarget.indexOf(target[a]) == -1 ) {\n newTarget.push(target[a]);\n }\n }\n }\n \n if ( target.length > 0 ) {\n \n // if collection, comparison will be done uppon the `id` attribute\n if (\n typeof(options[0]) != 'undefined' \n && typeof (options[0]) == 'object' \n && options[0] != null \n && typeof(options[0][keyComparison]) != 'undefined'\n && typeof(target[0]) == 'object' \n && typeof(target[0][keyComparison]) != 'undefined'\n ) {\n\n newTarget = (Array.isArray(target)) ? Array.from(target) : JSON.clone(target);\n var _options = JSON.clone(options);\n var next = null;\n \n i = 0;\n a = 0; aLen = newTarget.length;\n for (; a < aLen; ++a) {\n newTargetIds.push(newTarget[a][keyComparison]);\n }\n a = 0;\n for (; a < aLen; ++a) {\n \n end:\n for (var n = next || 0, nLen = _options.length; n < nLen; ++n) {\n \n if (\n _options[n] != null && typeof(_options[n][keyComparison]) != 'undefined' && _options[n][keyComparison] !== newTarget[a][keyComparison]\n\n ) {\n \n if ( newTargetIds.indexOf(_options[n][keyComparison]) == -1 ) {\n newTarget.push(_options[n]);\n newTargetIds.push(_options[n][keyComparison]);\n\n next = n+1; \n\n if (aLen < nLen)\n ++aLen;\n\n break end; \n }\n \n } else if( _options[n] != null && typeof(_options[n][keyComparison]) != 'undefined' && _options[n][keyComparison] === newTarget[a][keyComparison] ) {\n\n next = n+1;\n\n //break end;\n\n } else {\n break end;\n }\n }\n\n\n }\n\n return newTarget;\n\n\n } else { // normal case `arrays`\n a = 0;\n for (; a < options.length; ++a ) {\n if ( target.indexOf(options[a]) > -1 && override) {\n target.splice(target.indexOf(options[a]), 1, options[a])\n } else if ( typeof(newTarget[a]) == 'undefined' && typeof(options[a]) == 'object' ) {\n // merge using index \n newTarget = target;\n\n if (typeof (newTarget[a]) == 'undefined')\n newTarget[a] = {};\n \n \n for (let k in options[a]) {\n if (!newTarget[a].hasOwnProperty(k)) {\n newTarget[a][k] = options[a][k]\n }\n } \n \n } else {\n // fixing a = [25]; b = [25,25];\n // result must be [25,25]\n if (\n !override\n && newTarget.indexOf(options[a]) > -1 \n && typeof(options[a]) == 'number'\n // ok but not if @ same position\n //&& options[a] !== newTarget[a]\n ) {\n if (options[a] !== newTarget[a]) {\n newTarget.push(options[a]);\n continue\n }\n \n //break;\n }\n \n \n if (\n typeof (target[a]) != 'undefined'\n && !/null/i.test(target[a])\n && typeof (target[a][keyComparison]) != 'undefined'\n && typeof (options[a]) != 'undefined'\n && typeof (options[a][keyComparison]) != 'undefined'\n && target[a][keyComparison] == options[a][keyComparison]\n ) {\n if (override)\n newTarget[a] = options[a]\n else\n newTarget[a] = target[a]\n } else if (newTarget.indexOf(options[a]) == -1 /**&& typeof(options[a]) == 'string'*/) {\n newTarget.push(options[a]);\n }\n \n \n }\n }\n }\n\n\n }\n\n if ( newTarget.length > 0 && target.length > 0 || newTarget.length == 0 && target.length == 0 ) {\n return newTarget\n }\n }\n mergeArray.prototype.setKeyComparison = function(keyComparison) {\n this.keyComparison = keyComparison\n }\n\n\n /**\n * Check if object before merging.\n * */\n var isObject = function (obj) {\n if (\n !obj\n || {}.toString.call(obj) !== '[object Object]'\n || obj.nodeType\n || obj.setInterval\n ) {\n return false\n }\n\n var hasOwn = {}.hasOwnProperty;\n var hasOwnConstructor = hasOwn.call(obj, 'constructor');\n // added test for node > v6\n var hasMethodPrototyped = ( typeof(obj.constructor) != 'undefined' ) ? hasOwn.call(obj.constructor.prototype, 'isPrototypeOf') : false;\n\n\n if (\n obj.constructor && !hasOwnConstructor && !hasMethodPrototyped\n ) {\n return false\n }\n\n //Own properties are enumerated firstly, so to speed up,\n //if last one is own, then all properties are own.\n var key;\n return key === undefined || hasOwn.call(obj, key)\n }\n\n browse.setKeyComparison = function(keyComparison) {\n \n mergeArray.keyComparison = keyComparison;\n \n return browse\n }\n \n browse.getKeyComparison = function() {\n \n var keyComparison = mergeArray.keyComparison || 'id';\n \n // reset for the next merge\n mergeArray.keyComparison = 'id';\n \n return keyComparison\n }\n \n // clone target & source to prevent mutations from the originals\n // if (!browse.originalValueshasBeenCached) { \n // for (let a = 0, aLen = arguments.length; a < aLen; a++) {\n // if ( typeof(arguments[a]) == 'object' ) {\n // arguments[a] = JSON.clone(arguments[a]);\n // }\n // }\n // browse.originalValueshasBeenCached = true; \n // }\n \n return browse\n}\n\nif ( ( typeof(module) !== 'undefined' ) && module.exports ) {\n // for unit tests\n if ( typeof(JSON.clone) == 'undefined' ) {\n require('../../../helpers');\n }\n // Publish as node.js module\n module.exports = Merge()\n} else if ( typeof(define) === 'function' && define.amd) {\n // Publish as AMD module\n define( 'utils/merge',[],function() { return Merge() })\n};\n",
35
35
  "function registerEvents(plugin, events) {\n gina.registeredEvents[plugin] = events\n}\nfunction mergeEventProps(evt, proxiedEvent) {\n for (let p in proxiedEvent) {\n // add only missing props\n if ( typeof(evt[p]) == 'undefined' ) {\n evt[p] = proxiedEvent[p];\n }\n }\n return evt;\n}\n/**\n * addListener\n * \n * @param {object} target \n * @param {object} element \n * @param {string|array} name \n * @param {callback} callback \n */\nfunction addListener(target, element, name, callback) {\n \n var registerListener = function(target, element, name, callback) {\n \n if ( typeof(target.event) != 'undefined' && target.event.isTouchSupported && /^(click|mouseout|mouseover)/.test(name) && target.event[name].indexOf(element) == -1) {\n target.event[name][target.event[name].length] = element\n }\n\n if (typeof(element) != 'undefined' && element != null) {\n if (element.addEventListener) {\n element.addEventListener(name, callback, false)\n } else if (element.attachEvent) {\n element.attachEvent('on' + name, callback)\n }\n } else {\n target.customEvent.addListener(name, callback)\n }\n\n gina.events[name] = ( typeof(element.id) != 'undefined' && typeof(element.id) != 'object' ) ? element.id : element.getAttribute('id');\n }\n \n var i = 0, len = null;\n if ( Array.isArray(name) ) { \n len = name.length; \n for (; i < len; i++) {\n registerListener(target, element, name[i], callback)\n }\n } else {\n if ( Array.isArray(element) ) {\n i = 0;\n len = element.length;\n for (; i < len; i++) {\n let evtName = ( /\\.$/.test(name) ) ? name + element[i].id : name;\n registerListener(target, element[i], evtName, callback);\n }\n } else {\n name = ( /\\.$/.test(name) ) ? name + element.id : name;\n registerListener(target, element, name, callback);\n } \n }\n \n}\n/**\n * triggerEvent\n * @param {object} target - targeted domain\n * @param {object} element - HTMLFormElement \n * @param {string} name - event ID\n * @param {object|array|string} args - details\n * @param {object} [proxiedEvent]\n */\nfunction triggerEvent (target, element, name, args, proxiedEvent) {\n if (typeof(element) != 'undefined' && element != null) {\n var evt = null, isDefaultPrevented = false, isAttachedToDOM = false, merge = null;\n // if (proxiedEvent) {\n // merge = require('utils/merge');\n // }\n // done separately because it can be listen at the same time by the user & by gina\n if ( jQuery ) { //thru jQuery if detected\n\n // Check if listener is in use: e.g $('#selector').on('eventName', cb)\n var $events = null; // attached events list\n // Before jQuery 1.7\n var version = jQuery['fn']['jquery'].split(/\\./);\n if (version.length > 2) {\n version = version.splice(0,2).join('.');\n } else {\n version = version.join('.');\n }\n\n if (version <= '1.7') {\n $events = jQuery(element)['data']('events')\n } else {// From 1.8 +\n $events = jQuery['_data'](jQuery(element)[0], \"events\")\n }\n\n isAttachedToDOM = ( typeof($events) != 'undefined' && typeof($events[name]) != 'undefined' ) ? true : false;\n\n if (isAttachedToDOM) { // only trigger if attached\n evt = jQuery.Event( name );\n jQuery(element)['trigger'](evt, args);\n isDefaultPrevented = evt['isDefaultPrevented']();\n }\n\n\n }\n \n if (window.CustomEvent || document.createEvent) {\n \n \n if (window.CustomEvent) { // new method from ie9 \n evt = new CustomEvent(name, {\n 'detail' : args,\n 'bubbles' : true,\n 'cancelable': true,\n 'target' : element\n })\n } else { // before ie9\n\n evt = document.createEvent('HTMLEvents');\n // OR\n // evt = document.createEvent('Event');\n\n evt['detail'] = args;\n evt['target'] = element;\n evt.initEvent(name, true, true);\n\n evt['eventName'] = name;\n\n }\n if (proxiedEvent) {\n // merging props \n evt = mergeEventProps(evt, proxiedEvent);\n }\n\n if ( typeof(evt.defaultPrevented) != 'undefined' && evt.defaultPrevented )\n isDefaultPrevented = evt.defaultPrevented;\n\n if ( !isDefaultPrevented ) {\n //console.log('dispatching ['+name+'] to ', element.id, isAttachedToDOM, evt.detail);\n element.dispatchEvent(evt)\n }\n\n } else if (document.createEventObject) { // non standard\n \n evt = document.createEventObject();\n evt.srcElement.id = element.id;\n evt.detail = args;\n evt.target = element;\n \n if (proxiedEvent) { \n // merging props \n evt = mergeEventProps(evt, proxiedEvent);\n }\n \n element.fireEvent('on' + name, evt);\n }\n\n } else {\n target.customEvent.fire(name, args);\n }\n}\n\nfunction cancelEvent(event) {\n if (typeof(event) != 'undefined' && event != null) {\n\n event.cancelBubble = true;\n\n if (event.preventDefault) {\n event.preventDefault()\n }\n\n if (event.stopPropagation) {\n event.stopPropagation()\n }\n\n\n event.returnValue = false;\n }\n}\n\nfunction setupXhr(options) {\n var xhr = null;\n if (window.XMLHttpRequest) { // Mozilla, Safari, ...\n xhr = new XMLHttpRequest();\n } else if (window.ActiveXObject) { // IE\n try {\n xhr = new ActiveXObject(\"Msxml2.XMLHTTP\");\n } catch (e) {\n try {\n xhr = new ActiveXObject(\"Microsoft.XMLHTTP\");\n }\n catch (e) {}\n }\n }\n if ( typeof(options) != 'undefined' ) {\n if ( !options.url || typeof(options.url) == 'undefined' ) {\n throw new Error('Missing `options.url`');\n }\n if ( typeof(options.method) == 'undefined' ) {\n options.method = 'GET';\n }\n options.method = options.method.toUpperCase();\n \n if ( options.withCredentials ) {\n if ('withCredentials' in xhr) {\n // XHR for Chrome/Firefox/Opera/Safari.\n if (options.isSynchrone) {\n xhr.open(options.method, options.url, options.isSynchrone)\n } else {\n xhr.open(options.method, options.url)\n }\n } else if ( typeof XDomainRequest != 'undefined' ) {\n // XDomainRequest for IE.\n xhr = new XDomainRequest();\n xhr.open(options.method, options.url);\n } else {\n // CORS not supported.\n xhr = null;\n result = 'CORS not supported: the server is missing the header `\"Access-Control-Allow-Credentials\": true` ';\n triggerEvent(gina, $target, 'error.' + id, result);\n\n return;\n }\n \n if ( typeof(options.responseType) != 'undefined' ) {\n xhr.responseType = options.responseType;\n } else {\n xhr.responseType = '';\n }\n\n xhr.withCredentials = true;\n } else {\n if (options.isSynchrone) {\n xhr.open(options.method, options.url, options.isSynchrone);\n } else {\n xhr.open(options.method, options.url);\n }\n }\n\n // setting up headers - all but Content-Type ; it will be set right before .send() is called\n for (var hearder in options.headers) {\n //if ( hearder == 'Content-Type' && typeof (enctype) != 'undefined' && enctype != null && enctype != '') {\n // options.headers[hearder] = enctype\n //}\n if (hearder == 'Content-Type' && typeof (enctype) != 'undefined' && enctype != null && enctype != '')\n continue;\n\n xhr.setRequestHeader(hearder, options.headers[hearder]);\n }\n }\n return xhr;\n}\n\n/**\n * handleXhr\n * \n * @param {object} xhr - instance\n * @param {object} $el - dom objet element \n * @param {object} options \n */ \nfunction handleXhr(xhr, $el, options, require) {\n \n if (!xhr)\n throw new Error('No `xhr` object initiated');\n \n //var merge = require('utils/merge');\n \n var blob = null\n , isAttachment = null // handle download\n , contentType = null\n , result = null \n , id = null\n , $link = options.$link || null\n , $form = options.$form || null\n , $target = null\n ;\n delete options.$link;\n delete options.$form;\n \n if ($form || $link) {\n if ($link) {\n // not the link element but the link elements collection : like for popins main container\n $link.target = document.getElementById($link.id);\n $target = gina.link.target;\n id = gina.link.id;\n \n // copy $el attributes to $target\n // for (var prop in $link) {\n // if ( !$target[prop] )\n // $target[prop] = $link[prop];\n // }\n } else { // forms\n $target = $form.target;\n id = $target.getAttribute('id');\n } \n } else {\n $target = $el;\n id = $target.getAttribute('id');\n }\n \n // forward callback to HTML data event attribute through `hform` status\n var hLinkIsRequired = ( $link && $el.getAttribute('data-gina-link-event-on-success') || $link && $el.getAttribute('data-gina-link-event-on-error') ) ? true : false; \n // if (hLinkIsRequired && $link)\n // listenToXhrEvents($link, 'link');\n \n // forward callback to HTML data event attribute through `hform` status\n var hFormIsRequired = ( $form && $target.getAttribute('data-gina-form-event-on-submit-success') || $form && $target.getAttribute('data-gina-form-event-on-submit-error') ) ? true : false;\n // success -> data-gina-form-event-on-submit-success\n // error -> data-gina-form-event-on-submit-error\n if (hFormIsRequired && $form)\n listenToXhrEvents($form, 'form');\n \n \n // to upload, use `multipart/form-data` for `enctype`\n var enctype = $el.getAttribute('enctype') || options.headers['Content-Type'];\n \n // setting up headers - all but Content-Type ; it will be set right before .send() is called\n for (var hearder in options.headers) {\n //if ( hearder == 'Content-Type' && typeof (enctype) != 'undefined' && enctype != null && enctype != '') {\n // options.headers[hearder] = enctype\n //}\n if (hearder == 'Content-Type' && typeof (enctype) != 'undefined' && enctype != null && enctype != '')\n continue;\n\n xhr.setRequestHeader(hearder, options.headers[hearder]);\n } \n xhr.withCredentials = ( typeof(options.withCredentials) != 'undefined' ) ? options.withCredentials : false;\n \n \n // catching errors\n xhr.onerror = function(event, err) {\n \n var error = 'Transaction error: might be due to the server CORS settings.\\nPlease, check the console for more details.';\n var result = {\n 'status': xhr.status || 500, //500,\n 'error' : error\n }; \n \n var resultIsObject = true;\n if ($form)\n $form.eventData.error = result;\n \n if ($link)\n $link.eventData.error = result;\n \n //updateToolbar(result, resultIsObject);\n window.ginaToolbar.update('data-xhr', result, resultIsObject);\n \n triggerEvent(gina, $target, 'error.' + id, result);\n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', result);\n \n if (hLinkIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hlink', result);\n }\n \n // catching ready state cb\n xhr.onreadystatechange = function (event) {\n // In case the user is also redirecting\n var redirectDelay = (/Google Inc/i.test(navigator.vendor)) ? 50 : 0;\n \n if (xhr.readyState == 2) { // responseType interception\n isAttachment = ( /^attachment\\;/.test( xhr.getResponseHeader('Content-Disposition') ) ) ? true : false; \n // force blob response type\n if ( !xhr.responseType && isAttachment ) {\n xhr.responseType = 'blob';\n }\n }\n\n if (xhr.readyState == 4) {\n blob = null;\n contentType = xhr.getResponseHeader('Content-Type'); \n \n // 200, 201, 201' etc ...\n if( /^2/.test(xhr.status) ) {\n\n try { \n \n // handling blob xhr download\n if ( /blob/.test(xhr.responseType) || isAttachment ) {\n if ( typeof(contentType) == 'undefined' || contentType == null) {\n contentType = 'application/octet-stream';\n }\n \n blob = new Blob([this.response], { type: contentType });\n \n //Create a link element, hide it, direct it towards the blob, and then 'click' it programatically\n var a = document.createElement('a');\n a.style = 'display: none';\n document.body.appendChild(a);\n //Create a DOMString representing the blob and point the link element towards it\n var url = window.URL.createObjectURL(blob);\n a.href = url;\n var contentDisposition = xhr.getResponseHeader('Content-Disposition');\n a.download = contentDisposition.match('\\=(.*)')[0].substr(1);\n //programatically click the link to trigger the download\n a.click();\n //release the reference to the file by revoking the Object URL\n window.URL.revokeObjectURL(url);\n \n result = {\n status : xhr.status,\n statusText : xhr.statusText,\n responseType : blob.type,\n type : blob.type,\n size : blob.size \n }\n \n } \n\n \n if ( !result && /\\/json/.test( contentType ) ) {\n result = JSON.parse(xhr.responseText);\n \n if ( typeof(result.status) == 'undefined' )\n result.status = xhr.status || 200;\n }\n \n if ( !result && /\\/html/.test( contentType ) ) {\n \n result = {\n contentType : contentType,\n content : xhr.responseText\n };\n \n if ( typeof(result.status) == 'undefined' )\n result.status = xhr.status;\n \n // if hasPopinHandler & popinIsBinded\n if ( typeof(gina.popin) != 'undefined' && gina.hasPopinHandler ) {\n \n // select popin by id\n var $popin = gina.popin.getActivePopin();\n \n if ($popin) {\n \n XHRData = {};\n // update toolbar\n \n try {\n XHRData = new DOMParser().parseFromString(result.content, 'text/html').getElementById('gina-without-layout-xhr-data');\n XHRData = JSON.parse(decodeURIComponent(XHRData.value));\n \n XHRView = new DOMParser().parseFromString(result.content, 'text/html').getElementById('gina-without-layout-xhr-view'); \n XHRView = JSON.parse(decodeURIComponent(XHRView.value));\n \n // update data tab \n if ( gina && typeof(window.ginaToolbar) && typeof(XHRData) != 'undefined' ) {\n window.ginaToolbar.update('data-xhr', XHRData);\n }\n \n // update view tab \n if ( gina && typeof(window.ginaToolbar) && typeof(XHRView) != 'undefined' ) {\n window.ginaToolbar.update('view-xhr', XHRView);\n } \n\n } catch (err) {\n throw err\n } \n \n $popin.loadContent(result.content);\n \n result = XHRData;\n triggerEvent(gina, $target, 'success.' + id, result);\n \n return;\n } \n \n }\n }\n \n if (!result) { // normal case\n result = xhr.responseText; \n }\n \n if ($form)\n $form.eventData.success = result;\n\n XHRData = result;\n // update toolbar\n if ( gina && typeof(window.ginaToolbar) == 'object' && XHRData ) {\n try {\n // don't refresh for html datas\n if ( typeof(XHRData) != 'undefined' && /\\/html/.test(contentType) ) {\n window.ginaToolbar.update('data-xhr', XHRData);\n }\n\n } catch (err) {\n throw err\n }\n }\n\n triggerEvent(gina, $target, 'success.' + id, result);\n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'success.' + id + '.hform', result);\n \n if (hLinkIsRequired)\n triggerEvent(gina, $target, 'success.' + id + '.hlink', result);\n \n } catch (err) {\n\n result = {\n status: 422,\n error : err.message,\n stack : err.stack\n\n };\n \n if ($form)\n $form.eventData.error = result;\n \n\n XHRData = result; \n // update toolbar\n if ( gina && typeof(window.ginaToolbar) == 'object' && XHRData ) {\n try {\n\n if ( typeof(XHRData) != 'undefined' ) {\n window.ginaToolbar.update('data-xhr', XHRData);\n }\n\n } catch (err) {\n throw err\n }\n }\n\n triggerEvent(gina, $target, 'error.' + id, result);\n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', result);\n \n if (hLinkIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hlink', result);\n }\n \n // handle redirect\n if ( typeof(result) != 'undefined' && typeof(result.location) != 'undefined' ) { \n window.location.hash = ''; //removing hashtag \n \n // if ( window.location.host == gina.config.hostname && /^(http|https)\\:\\/\\//.test(result.location) ) { // same origin\n // result.location = result.location.replace( new RegExp(gina.config.hostname), '' );\n // } else { // external - need to remove `X-Requested-With` from `options.headers`\n result.location = (!/^http/.test(result.location) && !/^\\//.test(result.location) ) ? location.protocol +'//' + result.location : result.location;\n //} \n \n return setTimeout(() => {\n window.location.href = result.location;\n }, redirectDelay); \n }\n\n } else if ( xhr.status != 0) {\n \n result = { 'status': xhr.status, 'message': '' };\n // handling blob xhr error\n if ( /blob/.test(xhr.responseType) ) {\n \n blob = new Blob([this.response], { type: 'text/plain' });\n \n var reader = new FileReader(), blobError = '';\n \n // This fires after the blob has been read/loaded.\n reader.addEventListener('loadend', (e) => {\n \n if ( /string/i.test(typeof(e.srcElement.result)) ) {\n blobError += e.srcElement.result;\n } else if ( typeof(e.srcElement.result) == 'object' ) {\n result = merge(result, e.srcElement.result)\n } else {\n result.message += e.srcElement.result\n }\n \n // once ready\n if ( /^2/.test(reader.readyState) ) {\n \n if ( /^(\\{|\\[)/.test( blobError ) ) {\n try {\n result = merge( result, JSON.parse(blobError) )\n } catch(err) {\n result = merge(result, err)\n } \n }\n \n if (!result.message)\n delete result.message;\n \n if ($form)\n $form.eventData.error = result;\n\n // forward appplication errors to forms.errors when available\n if ( typeof(result) != 'undefined' && typeof(result.error) != 'undefined' && result.error.fields && typeof(result.error.fields) == 'object') {\n var formsErrors = {}, errCount = 0;\n for (var f in result.error.fields) {\n ++errCount;\n formsErrors[f] = { isApplicationValidationError: result.error.fields[f] };\n }\n\n if (errCount > 0) {\n handleErrorsDisplay($form.target, formsErrors);\n }\n }\n\n // update toolbar\n XHRData = result;\n if ( gina && typeof(window.ginaToolbar) == 'object' && XHRData ) {\n try {\n // update toolbar\n window.ginaToolbar.update('data-xhr', XHRData );\n\n } catch (err) {\n throw err\n }\n }\n\n triggerEvent(gina, $target, 'error.' + id, result);\n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', result);\n \n if (hLinkIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hlink', result);\n }\n return;\n \n \n });\n\n // Start reading the blob as text.\n reader.readAsText(blob);\n \n } else { // normal case\n \n if ( /^(\\{|\\[).test( xhr.responseText ) /) {\n\n try {\n result = merge( result, JSON.parse(xhr.responseText) )\n } catch (err) {\n result = merge(result, err)\n }\n\n } else if ( typeof(xhr.responseText) == 'object' ) {\n result = merge(result, xhr.responseText)\n } else {\n result.message = xhr.responseText\n }\n\n if ($form)\n $form.eventData.error = result;\n\n // forward appplication errors to forms.errors when available\n if ( typeof(result) != 'undefined' && typeof(result.error) != 'undefined' && result.error.fields && typeof(result.error.fields) == 'object') {\n var formsErrors = {}, errCount = 0;\n for (var f in result.error.fields) {\n ++errCount;\n formsErrors[f] = { isApplicationValidationError: result.error.fields[f] };\n }\n\n if (errCount > 0) {\n handleErrorsDisplay($form.target, formsErrors);\n }\n }\n\n // update toolbar\n XHRData = result;\n if ( gina && typeof(window.ginaToolbar) == \"object\" && XHRData ) {\n try {\n // update toolbar\n window.ginaToolbar.update('data-xhr', XHRData );\n\n } catch (err) {\n throw err\n }\n }\n\n triggerEvent(gina, $target, 'error.' + id, result);\n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', result);\n \n if (hLinkIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hlink', result); \n }\n \n return;\n\n \n }\n }\n };\n \n // catching request progress\n xhr.onprogress = function(event) {\n \n var percentComplete = '0';\n if (event.lengthComputable) {\n percentComplete = event.loaded / event.total;\n percentComplete = parseInt(percentComplete * 100);\n\n }\n\n //var percentComplete = (event.position / event.totalSize)*100;\n var result = {\n 'status': 100,\n 'progress': percentComplete\n };\n\n if ($form)\n $form.eventData.onprogress = result;\n\n triggerEvent(gina, $target, 'progress.' + id, result);\n return;\n };\n\n // catching timeout\n xhr.ontimeout = function (event) {\n result = {\n 'status': 408,\n 'error': 'Request Timeout'\n };\n\n if ($form)\n $form.eventData.ontimeout = result;\n\n triggerEvent(gina, $target, 'error.' + id, result);\n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', result);\n \n if (hLinkIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hlink', result);\n \n return;\n };\n \n \n //return xhr;\n}\n\nfunction removeListener(target, element, name, callback) {\n if (typeof(target.event) != 'undefined' && target.event.isTouchSupported && /^(click|mouseout|mouseover)/.test(name) && target.event[name].indexOf(element) != -1) {\n target.event[name].splice(target.event[name].indexOf(element), 1)\n }\n\n if (typeof(element) != 'undefined' && element != null) {\n if (element.removeEventListener) {\n //element.removeEventListener(name, callback, false);\n if ( Array.isArray(element) ) {\n i = 0;\n len = element.length;\n for (; i < len; i++) {\n let evtName = ( /\\.$/.test(name) ) ? name + element[i].id : name;\n element.removeEventListener(evtName, callback, false);\n if ( typeof(gina.events[evtName]) != 'undefined' ) {\n // removed ------> [evtName];\n delete gina.events[evtName]\n }\n }\n } else {\n name = ( /\\.$/.test(name) ) ? name + element.id : name;\n element.removeEventListener(name, callback, false);\n } \n } else if (element.attachEvent) {\n //element.detachEvent('on' + name, callback);\n if ( Array.isArray(element) ) {\n i = 0;\n len = element.length;\n for (; i < len; i++) {\n let evtName = ( /\\.$/.test(name) ) ? name + element[i].id : name;\n element.detachEvent('on' + evtName, callback);\n if ( typeof(gina.events[evtName]) != 'undefined' ) {\n // removed ------> [evtName];\n delete gina.events[evtName]\n }\n }\n } else {\n name = ( /\\.$/.test(name) ) ? name + element.id : name;\n element.detachEvent('on' + name, callback);\n } \n }\n } else {\n //target.customEvent.removeListener(name, callback)\n if ( Array.isArray(element) ) {\n i = 0;\n len = element.length;\n for (; i < len; i++) {\n let evtName = ( /\\.$/.test(name) ) ? name + element[i].id : name;\n target.customEvent.removeListener(evtName, callback);\n if ( typeof(gina.events[evtName]) != 'undefined' ) {\n // removed ------> [evtName];\n delete gina.events[evtName]\n }\n }\n } else {\n name = ( /\\.$/.test(name) ) ? name + element.id : name;\n target.customEvent.removeListener(name, callback)\n } \n }\n\n if ( typeof(gina.events[name]) != 'undefined' ) {\n // removed ------> [name];\n delete gina.events[name]\n }\n if ( typeof(callback) != 'undefined' ) {\n callback()\n }\n}\n\n\n\nfunction on(event, cb) {\n\n if (!this.plugin) throw new Error('No `plugin` reference found for this event: `'+ event);\n\n var events = gina.registeredEvents[this.plugin];\n\n if ( events.indexOf(event) < 0 && !/^init$/.test(event) && !/\\.hform$/.test(event) && !/\\.hlink$/.test(event) ) {\n cb(new Error('Event `'+ event +'` not handled by ginaEventHandler'))\n } else {\n var $target = null, id = null;\n if ( typeof(this.id) != 'undefined' && typeof(this.id) != 'object' ) {\n $target = this.target || this;\n id = this.id;\n } else if ( typeof(this.target) != 'undefined' ) {\n $target = this.target;\n if (!$target) {\n $target = this;\n }\n id = ( typeof($target.getAttribute) != 'undefined' ) ? $target.getAttribute('id') : this.id;\n } else {\n $target = this.target;\n id = instance.id;\n }\n\n if ( this.eventData && !$target.eventData)\n $target.eventData = this.eventData\n\n if ( /\\.(hform|hlink)$/.test(event) ) { \n event = ( /\\.hform$/.test(event) ) ? event.replace(/\\.hform$/, '.' + id + '.hform') : event.replace(/\\.hlink$/, '.' + id + '.hlink');\n } else { // normal case\n event += '.' + id;\n }\n \n\n if (!gina.events[event]) {\n\n addListener(gina, $target, event, function(e) {\n\n //if ( typeof(e.defaultPrevented) != 'undefined' && e.defaultPrevented)\n cancelEvent(e);\n\n var data = null;\n\n if (e['detail']) {\n data = e['detail'];\n } else if ( typeof(this.eventData.submit) != 'undefined' ) {\n data = this.eventData.submit\n } else if ( typeof(this.eventData.error) != 'undefined' ) {\n data = this.eventData.error;\n } else if ( typeof(this.eventData.success) != 'undefined' ) {\n data = this.eventData.success;\n }\n\n if (cb)\n cb(e, data);\n \n //triggerEvent(gina, e.currentTarget, e.type);\n });\n\n if (this.initialized && !this.isReady)\n triggerEvent(gina, $target, 'init.' + id);\n\n }\n\n return this\n }\n \n // Nothing can be added after on() \n \n \n var listenToXhrEvents = function($el, type) {\n\n\n //data-gina-{type}-event-on-success\n var htmlSuccesEventCallback = $el.target.getAttribute('data-gina-'+ type +'-event-on-success') || null;\n if (htmlSuccesEventCallback != null) {\n\n if ( /\\((.*)\\)/.test(htmlSuccesEventCallback) ) {\n eval(htmlSuccesEventCallback)\n } else {\n $el.on('success.h'+ type, window[htmlSuccesEventCallback])\n }\n }\n\n //data-gina-{type}-event-on-error\n var htmlErrorEventCallback = $el.target.getAttribute('data-gina-'+ type +'-event-on-error') || null;\n if (htmlErrorEventCallback != null) {\n if ( /\\((.*)\\)/.test(htmlErrorEventCallback) ) {\n eval(htmlErrorEventCallback)\n } else {\n $el.on('error.h'+ type, window[htmlErrorEventCallback])\n }\n }\n }\n};\ndefine(\"utils/events\", function(){});\n\n",
36
36
  "function PrototypesHelper(instance) {\n \n var local = instance || null; \n \n // dateFormat proto\n if ( typeof(local) != 'undefined' && typeof(local.dateFormat) != 'undefined' ) {\n for (let method in local.dateFormat) {\n \n if ( typeof(Date[method]) != 'undefined' )\n continue;\n \n Object.defineProperty( Date.prototype, method, {\n writable: false,\n enumerable: false,\n //If loaded several times, it can lead to an exception. That's why I put this.\n configurable: true,\n value: function() { \n \n var newArgs = { 0: this }, i = 1;\n for (var a in arguments) {\n newArgs[i] = arguments[a];\n ++i\n }\n newArgs.length = i;\n // don't touch this, we need the name\n const name = method;\n \n return local.dateFormat[name].apply(this, newArgs );\n }\n });\n \n }\n }\n\n if ( typeof(Array.clone) == 'undefined' ) {\n /**\n * clone array\n * \n * @return {array} Return cloned array\n * @supress {misplacedTypeAnnotation}\n **/\n Object.defineProperty( Array.prototype, 'clone', {\n writable: false,\n enumerable: false,\n //If loaded several times, it can lead to an exception. That's why I put this.\n configurable: true,\n value: function(){ return this.slice(0); }\n });\n }\n \n if ( typeof(JSON.clone) == 'undefined' ) {\n /**\n * JSON.clone\n * Clone JSON object\n * \n * Changes made here must be reflected in: \n * - gina/utils/prototypes.js\n * - gina/framework/version/helpers/prototypes.js\n * - gina/framework/version/core/asset/js/plugin/src/gina/utils/polyfill.js\n * \n * @param {object} source\n * @param {object} [target]\n * \n * @return {object} cloned JSON object\n **/\n \n var clone = function(source, target) {\n // if ( source === undefined) {\n // source = null;\n // }\n if (source == null || typeof source != 'object') return source;\n if (source.constructor != Object && source.constructor != Array) return source;\n if (source.constructor == Date || source.constructor == RegExp || source.constructor == Function ||\n source.constructor == String || source.constructor == Number || source.constructor == Boolean)\n return new source.constructor(source);\n\n try {\n target = target || new source.constructor();\n } catch (err) { \n throw err;\n }\n \n var i = 0\n , len = Object.getOwnPropertyNames(source).length || 0\n , keys = Object.keys(source)\n ;\n \n while (i<len) {\n let key = Object.getOwnPropertyNames(source)[i];\n if (key == 'undefined') {\n i++;\n continue;\n }\n if (source[key] === undefined) {\n var warn = new Error('JSON.clone(...) possible error detected: source['+key+'] is undefined !! Key `'+ key +'` should not be left `undefined`. Assigning to `null`');\n warn.stack = warn.stack.replace(/^Error\\:\\s+/g, '');\n if ( typeof(warn.message) != 'undefined' ) {\n warn.message = warn.message.replace(/^Error\\:\\s+/g, '');\n }\n console.warn(warn);\n target[key] = null\n } else {\n target[key] = (typeof target[key] == 'undefined' ) ? clone(source[key], null) : target[key];\n }\n \n i++;\n }\n i = null; len = null; keys = null;\n\n return target;\n };\n // TODO - add unit tests\n // TODO - decide which one we want to keep\n // Following code should have the same effect as the default code, but error are better handled\n \n // var clone = function(source, target) {\n // if (source == null || source == undefined || typeof source != 'object') return source;\n // if (source.constructor.name != 'Object' && source.constructor.name != 'Array') return source;\n // // if (\n // // source.constructor == Date \n // // || source.constructor == RegExp \n // // || source.constructor == Function \n // // || source.constructor == String \n // // || source.constructor == Number \n // // || source.constructor == Boolean\n // // ) {\n // // return new source.constructor(source)\n // // }\n \n // //target = target || new source.constructor();\n // target = ( typeof(target) != 'undefined' && target) ? target : new source.constructor();\n // var i = 0\n // , len = Object.getOwnPropertyNames(source).length || 0\n // , keys = Object.keys(source)\n // , error = null\n // ;\n \n // while (i<len) {\n // try {\n // //target[keys[i]] = (typeof target[keys[i]] == 'undefined') ? clone(source[keys[i]], null) : target[keys[i]];\n // if (typeof target[keys[i]] != 'undefined') {\n // ++i;\n // continue;\n // }\n // if ( typeof(source[keys[i]]) != 'undefined' ) {\n // let _source = source[keys[i]];\n // if (/^null|undefined$/i.test(_source)) {\n // target[keys[i]] = _source\n // } \n // else if (\n // _source.constructor.name == 'Date'\n // || _source.constructor.name == 'RegExp'\n // || _source.constructor.name == 'Function'\n // || _source.constructor.name == 'String'\n // || _source.constructor.name == 'Number'\n // || _source.constructor.name == 'Boolean'\n // ) {\n // target[keys[i]] = _source\n // } \n // else if (\n // // _source.constructor.name == 'Date'\n // // || _source.constructor.name == 'RegExp'\n // // || _source.constructor.name == 'Function'\n // // || _source.constructor.name == 'String'\n // // || _source.constructor.name == 'Number'\n // // || _source.constructor.name == 'Boolean'\n // //|| \n // _source.constructor.name == 'Array'\n // //|| _source.constructor.name == 'Object'\n // ) {\n // //target[keys[i]] = new _source.constructor(_source)\n // target[keys[i]] = _source.slice()\n // }\n // else {\n // //target[keys[i]] = clone(_source[keys[i]], null)\n // target[keys[i]] = new _source.constructor(_source)\n // }\n // }\n\n // i++;\n // } catch (err) {\n // var errString = 'JSON.clone(...) error on constructor not supported: ['+ keys[i] +'] `'+ source.constructor.name +'`\\n'+ err.stack;\n // console.error(errString);\n // error = new Error(errString);\n // break;\n // } \n // }\n \n // if (error) {\n // throw error;\n // }\n \n // i = null; len = null; keys = null;\n\n // return target;\n \n // };\n \n \n \n // WHY NOT USE SOMETHING ELSE ?\n // Could have been fine, but not working when you have references pointing to another object\n // return Object.assign({}, source);\n // var clone = function(source, target) {\n // return Object.assign(target||{}, source);\n // };\n \n // Performences issue\n //return JSON.parse(JSON.stringify(source));\n // var clone = function(source) {\n // return JSON.parse(JSON.stringify(source));\n // };\n \n JSON.clone = clone;\n \n }\n \n if ( typeof(JSON.escape) == 'undefined' ) {\n /**\n * JSON.escape\n * Escape special characters\n * \n * Changes made here must be reflected in: \n * - gina/utils/prototypes.js\n * - gina/framework/version/helpers/prototypes.js\n * - gina/framework/version/core/asset/js/plugin/src/gina/utils/polyfill.js\n * \n * @param {object} jsonStr\n * \n * @return {object} escaped JSON string\n **/\n var escape = function(jsonStr){\n try {\n return jsonStr\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\t/g, \"\\\\t\")\n ;\n } catch (err) { \n throw err;\n }\n };\n \n JSON.escape = escape;\n }\n \n\n if ( typeof(Array.toString) == 'undefined' ) {\n Array.prototype.toString = function(){\n return this.join();\n };\n }\n\n if ( typeof(Array.inArray) == 'undefined' ) {\n Object.defineProperty( Array.prototype, 'inArray', {\n writable: false,\n enumerable: false,\n //If loaded several times, it can lead to an exception. That's why I put this.\n configurable: true,\n value: function(o){ return this.indexOf(o)!=-1 }\n });\n }\n \n if ( typeof(Array.from) == 'undefined' ) { // if not under ES6\n\n Object.defineProperty( Array.prototype, 'from', {\n writable: false,\n enumerable: false,\n //If loaded several times, it can lead to an exception. That's why I put this.\n configurable: true,\n value: function(a){\n var seen = {}\n , out = []\n , len = a.length\n , j = 0;\n\n for(var i = 0; i < len; i++) {\n var item = a[i];\n if(seen[item] !== 1) {\n seen[item] = 1;\n out[j++] = item\n }\n }\n\n return out\n }\n });\n }\n \n if ( typeof(Object.count) == 'undefined' ) {\n Object.defineProperty( Object.prototype, 'count', {\n writable: true,\n enumerable: false,\n //If loaded several times, it can lead to an exception. That's why I put this.\n configurable: true,\n value: function(){\n var i = 0;\n try {\n var self = this;\n if (this instanceof String) self = JSON.parse(this);\n \n for (var prop in this)\n if (this.hasOwnProperty(prop)) ++i;\n\n return i;\n } catch (err) {\n return i;\n }\n\n }\n });\n } \n\n \n \n if ( typeof(global) != 'undefined' && typeof(global.__stack) == 'undefined' ) {\n /**\n * __stack Get current stack\n * @return {Object} stack Current stack\n * @suppress {es5Strict}\n **/\n Object.defineProperty(global, '__stack', {\n //If loaded several times, it can lead to an exception. That's why I put this.\n configurable: true,\n get: function(){\n var orig = Error.prepareStackTrace;\n Error.prepareStackTrace = function(_, stack){\n return stack;\n };\n var err = new Error;\n /** @suppress {es5Strict} */\n Error.captureStackTrace(err, arguments.callee);\n var stack = err.stack;\n Error.prepareStackTrace = orig;\n return stack;\n }\n });\n }\n \n \n}\n\nif ( ( typeof(module) !== 'undefined' ) && module.exports ) {\n // Publish as node.js module\n module.exports = PrototypesHelper\n} else if ( typeof(define) === 'function' && define.amd) {\n // Publish as AMD module\n define( 'helpers/prototypes',[],function() { return PrototypesHelper })\n}\n ;\n",
37
- "/*\n * This file is part of the gina package.\n * Copyright (c) 2009-2022 Rhinostone <contact@gina.io>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n/**\n * Credits & thanks to Steven Levithan :)\n * http://blog.stevenlevithan.com/archives/date-time-format\n * \n * \n * \n * Original Copyrights\n * Date Format 1.2.3\n * (c) 2007-2009 Steven Levithan <stevenlevithan.com>\n * MIT license\n *\n * Includes enhancements by Scott Trenda <scott.trenda.net>\n * and Kris Kowal <cixar.com/~kris.kowal/>\n *\n * Accepts a date, a mask, or a date and a mask.\n * Returns a formatted version of the given date.\n * The date defaults to the current date/time.\n * The mask defaults to dateFormat.masks.default.\n *\n * @param {string} date\n * @param {string} mask\n */\nfunction DateFormatHelper() {\n \n var isGFFCtx = ( ( typeof(module) !== 'undefined' ) && module.exports ) ? false : true;\n\n var merge = (isGFFCtx) ? require('utils/merge') : require('./../lib/merge');\n \n // if ( typeof(define) === 'function' && define.amd ) {\n // var Date = this.Date;\n // }\n \n var self = {};\n // language-country\n self.culture = 'en-US'; // by default\n self.lang = 'en'; // by default\n\n self.masks = {\n // i18n\n \"default\": \"ddd mmm dd yyyy HH:MM:ss\",\n shortDate: \"m/d/yy\",\n shortDate2: \"mm/dd/yyyy\",\n mediumDate: \"mmm d, yyyy\",\n longDate: \"mmmm d, yyyy\",\n fullDate: \"dddd, mmmm d, yyyy\",\n // common\n cookieDate: \"GMT:ddd, dd mmm yyyy HH:MM:ss\",\n logger: \"[yyyy mmm dd HH:MM:ss]\",\n shortTime: \"h:MM TT\",\n shortTime2: \"h:MM\",\n mediumTime: \"h:MM:ss TT\",\n mediumTime2: \"h:MM:ss\",\n longTime: \"h:MM:ss TT Z\",\n longTime2: \"h:MM:ss TT\",\n concatenatedDate: \"yyyymmdd\",\n isoDate: \"yyyy-mm-dd\",\n isoTime: \"HH:MM:ss\",\n shortIsoTime: \"HH:MM\",\n longIsoTime: \"HH:MM:ss TT\",\n isoDateTime: \"yyyy-mm-dd'T'HH:MM:ss\",\n isoUtcDateTime: \"UTC:yyyy-mm-dd'T'HH:MM:ss'Z'\"\n };\n \n self.i18n = {\n 'en': {\n dayNames: [\n \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\",\n \"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"\n ],\n monthNames: [\n \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n \"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"\n ],\n masks: {\n \"default\": \"ddd mmm dd yyyy HH:MM:ss\",\n shortDate: \"m/d/yy\",\n shortDate2: \"mm/dd/yyyy\",\n mediumDate: \"mmm d, yyyy\",\n longDate: \"mmmm d, yyyy\",\n fullDate: \"dddd, mmmm d, yyyy\"\n }\n },\n 'fr': {\n dayNames: [\n \"dim\", \"lun\", \"mar\", \"mer\", \"jeu\", \"ven\", \"sam\",\n \"dimanche\", \"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\", \"samedi\"\n ],\n monthNames: [\n \"Jan\", \"Fév\", \"Mar\", \"Avr\", \"Mai\", \"Jui\", \"Juil\", \"Aoû\", \"Sep\", \"Oct\", \"Nov\", \"Déc\",\n \"Janvier\", \"Février\", \"Mars\", \"Avril\", \"Mai\", \"Juin\", \"Juillet\", \"Août\", \"Septembre\", \"Octobre\", \"Novembre\", \"Décembre\"\n ],\n masks: {\n \"default\": \"ddd mmm dd yyyy HH:MM:ss\",\n shortDate: \"d/m/yy\",\n shortDate2: \"dd/mm/yyyy\",\n mediumDate: \"d mmm, yyyy\",\n longDate: \"d mmmm, yyyy\",\n fullDate: \"dddd, d mmmm, yyyy\"\n }\n }\n };\n \n /**\n * \n * @param {string} culture (5 chars) | lang (2 chars) \n */\n var setCulture = function(date, culture) {\n if (/\\-/.test(culture) ) {\n self.culture = culture;\n self.lang = culture.split(/\\-/)[0];\n } else {\n self.lang = culture\n } \n \n return this\n }\n\n var format = function(date, mask, utc) {\n var dF = self\n , i18n = dF.i18n[dF.lang] || dF.i18n['en']\n , masksList = merge(i18n.masks, dF.masks)\n ;\n \n if ( typeof(dF.i18n[dF.culture]) != 'undefined' ) {\n i18n = dF.i18n[dF.culture];\n if ( typeof(dF.i18n[dF.culture].mask) != 'undefined' ) {\n masksList = merge(i18n.masks, dF.masks)\n }\n }\n\n var\ttoken = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\\1?|[LloSZ]|\"[^\"]*\"|'[^']*'/g,\n timezone = /\\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\\d{4})?)\\b/g,\n timezoneClip = /[^-+\\dA-Z]/g,\n pad = function (val, len) {\n val = String(val);\n len = len || 2;\n while (val.length < len) val = \"0\" + val;\n return val;\n };\n\n // You can't provide utc if you skip other args (use the \"UTC:\" mask prefix)\n if (arguments.length == 1 && Object.prototype.toString.call(date) == \"[object String]\" && !/\\d/.test(date)) {\n mask = date;\n date = undefined;\n }\n\n // Passing date through Date applies Date.parse, if necessary\n date = date ? new Date(date) : new Date();\n if (isNaN(date)) throw SyntaxError(\"invalid date\");\n\n mask = String(masksList[mask] || mask || masksList[\"default\"]);\n\n // Allow setting the utc argument via the mask\n if (mask.slice(0, 4) == \"UTC:\") {\n mask = mask.slice(4);\n utc = true;\n }\n\n var\t_ = utc ? \"getUTC\" : \"get\",\n d = date[_ + \"Date\"](),\n D = date[_ + \"Day\"](),\n m = date[_ + \"Month\"](),\n y = date[_ + \"FullYear\"](),\n H = date[_ + \"Hours\"](),\n M = date[_ + \"Minutes\"](),\n s = date[_ + \"Seconds\"](),\n L = date[_ + \"Milliseconds\"](),\n o = utc ? 0 : date.getTimezoneOffset(),\n flags = {\n d: d,\n dd: pad(d),\n ddd: i18n.dayNames[D],\n dddd: i18n.dayNames[D + 7],\n m: m + 1,\n mm: pad(m + 1),\n mmm: i18n.monthNames[m],\n mmmm: i18n.monthNames[m + 12],\n yy: String(y).slice(2),\n yyyy: y,\n h: H % 12 || 12,\n hh: pad(H % 12 || 12),\n H: H,\n HH: pad(H),\n M: M,\n MM: pad(M),\n s: s,\n ss: pad(s),\n l: pad(L, 3),\n L: pad(L > 99 ? Math.round(L / 10) : L),\n t: H < 12 ? \"a\" : \"p\",\n tt: H < 12 ? \"am\" : \"pm\",\n T: H < 12 ? \"A\" : \"P\",\n TT: H < 12 ? \"AM\" : \"PM\",\n Z: utc ? \"UTC\" : (String(date).match(timezone) || [\"\"]).pop().replace(timezoneClip, \"\"),\n o: (o > 0 ? \"-\" : \"+\") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),\n S: [\"th\", \"st\", \"nd\", \"rd\"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]\n };\n\n\n\n return mask.replace(token, function ($0) {\n return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);\n });\n }\n\n /**\n * Get mask name from a given format\n *\n * @param {string} format\n *\n * @return {string} maskName\n * */\n // var getMaskNameFromFormat = function (format) {\n\n // var name = \"default\";\n\n // for (var f in self.masks) {\n // if ( self.masks[f] === format )\n // return f\n // }\n\n // return name\n // }\n\n\n /**\n * Count days from the current date to another\n *\n * TODO - add a closure to `ignoreWeekend()` based on Lib::Validator\n * TODO - add a closure to `ignoreFromList(array)` based on Lib::Validator\n *\n * @param {object} dateTo\n * @return {number} count\n * */\n var countDaysTo = function(date, dateTo) {\n\n if ( dateTo instanceof Date) {\n // The number of milliseconds in one day\n var oneDay = 1000 * 60 * 60 * 24\n\n // Convert both dates to milliseconds\n var date1Ms = date.getTime()\n var date2Ms = dateTo.getTime()\n\n // Calculate the difference in milliseconds\n var count = Math.abs(date1Ms - date2Ms)\n\n // Convert back to days and return\n return Math.round(count/oneDay);\n } else {\n throw new Error('dateTo is not instance of Date() !')\n }\n }\n\n /**\n * Will give an array of dates between the current date to a targeted date\n *\n * TODO - add a closure to `ignoreWeekend()` based on Utils::Validator\n * TODO - add a closure to `ignoreFromList(array)` based on Utils::Validator\n *\n * @param {object} dateTo\n * @param {string} [ mask ]\n *\n * @return {array} dates\n * */\n var getDaysTo = function(date, dateTo, mask) {\n\n if ( dateTo instanceof Date) {\n var count = countDaysTo(date, dateTo)\n , month = date.getMonth()\n , year = date.getFullYear()\n , day = date.getDate() + 1\n , dateObj = new Date(year, month, day)\n , days = []\n , i = 0;\n\n for (; i < count; ++i) {\n if ( typeof(mask) != 'undefined' ) {\n days.push(new Date(dateObj).format(mask));\n } else {\n days.push(new Date(dateObj));\n }\n\n dateObj.setDate(dateObj.getDate() + 1);\n }\n\n return days || [];\n } else {\n throw new Error('dateTo is not instance of Date() !')\n }\n }\n\n var getDaysInMonth = function(date) {\n var month = date.getMonth();\n var year = date.getFullYear();\n var dateObj = new Date(year, month, 1);\n var days = [];\n while (dateObj.getMonth() === month) {\n days.push(new Date(dateObj));\n dateObj.setDate(dateObj.getDate() + 1);\n }\n return days;\n }\n \n \n /**\n * getQuarter\n * Get quarter number\n * To test : https://planetcalc.com/1252/\n * Based on fiscal year- See.: https://en.wikipedia.org/wiki/Fiscal_year\n * \n * TODO - Complete fiscalCodes\n * \n * @param {object} [date] if not defined, will take today's value\n * @param {string} [code] - us|eu\n * \n * @return {number} quarterNumber - 1 to 4\n */\n var fiscalCodes = ['us', 'eu', 'corporate'];\n var getQuarter = function(date, code) {\n if (\n arguments.length == 1 \n && typeof(arguments[0]) == 'string'\n ) {\n if ( fiscalCodes.indexOf(arguments[0].toLowerCase()) < 0 ) {\n throw new Error('Quarter '+ arguments[0] +' code not supported !');\n }\n date = new Date();\n code = arguments[0]\n }\n if ( typeof(date) == 'undefined' ) {\n date = new Date();\n }\n if ( typeof(code) == 'undefined') {\n code = 'corporate';\n }\n \n code = code.toLowerCase();\n var q = [1,2,3,4]; // EU & corporates by default\n switch (code) {\n case 'us':\n q = [4,1,2,3];\n break;\n \n case 'corportate':\n case 'eu':\n q = [1,2,3,4]\n break;\n default:\n // EU & corporates by default\n q = [1,2,3,4];\n break;\n }\n \n return q[Math.floor(date.getMonth() / 3)];\n }\n \n /**\n * getHalfYear\n * \n * Based on fiscal year- See.: https://en.wikipedia.org/wiki/Fiscal_year\n * \n * @param {object} date \n * @param {string} code\n * \n * @return halfYear number - 1 to 2\n */\n var getHalfYear = function(date, code) {\n if (\n arguments.length == 1 \n && typeof(arguments[0]) == 'string'\n ) {\n if ( fiscalCodes.indexOf(arguments[0].toLowerCase()) < 0 ) {\n throw new Error('Quarter '+ arguments[0] +' code not supported !');\n }\n date = new Date();\n code = arguments[0]\n }\n if ( typeof(date) == 'undefined' ) {\n date = new Date();\n }\n if ( typeof(code) == 'undefined') {\n code = 'corporate';\n }\n \n code = code.toLowerCase();\n \n return (date.getQuarter(code) <=2 ) ? 1 : 2;\n }\n \n /**\n * getWeekISO8601\n * Get week number\n * ISO 8601\n * To test : https://planetcalc.com/1252/\n * \n * @param {object} [date] if not defined, will take today's value\n * \n * @return {number} weekNumber\n */\n var getWeekISO8601 = function(date) {\n // Copy date so don't modify original\n d = new Date(date.getFullYear(), date.getMonth(), date.getDate()); \n // Make Sunday's day number 7\n var dayNum = d.getDay() || 7;\n d.setDate(d.getDate() + 4 - dayNum);\n var yearStart = new Date(Date.parse(d.getFullYear(),0,1));\n \n return Math.ceil((((d - yearStart) / 86400000) + 1)/7)\n }\n \n /**\n * getWeek\n * Get week number\n * To test : https://planetcalc.com/1252/\n * \n * @param {object} [date] if not defined, will take today's value\n * \n * @return {number} weekNumber - 1 to 53\n */\n var getWeek = function(date, standardMethod) {\n if ( typeof(date) == 'undefined' ) {\n date = new Date();\n }\n if ( typeof(standardMethod) == 'undefined') {\n standardMethod = 'ISO 8601';\n }\n \n standardMethod = standardMethod.replace(/\\s+/g, '').toLowerCase();\n switch (standardMethod) {\n case 'corporate':\n case 'eu':\n case 'iso8601':\n return getWeekISO8601(date)\n \n default:\n return getWeekISO8601(date)\n }\n }\n\n /**\n * Add or subtract hours\n * Adding 2 hours\n * => myDate.addHours(2)\n * Subtracting 10 hours\n * => myDate.addHours(-10)\n * */\n var addHours = function(date, h) {\n var copiedDate = new Date(date.getTime());\n copiedDate.setHours(copiedDate.getHours() + h);\n return copiedDate;\n }\n\n\n /**\n * Add or subtract days\n * Adding 2 days\n * => myDate.addDays(2)\n * Subtracting 10 days\n * => myDate.addDays(-10)\n * */\n var addDays = function(date, d) {\n var copiedDate = new Date(date.getTime());\n copiedDate.setHours(copiedDate.getHours() + d * 24);\n return copiedDate;\n }\n\n /**\n * Add or subtract years\n * Adding 2 days\n * => myDate.addYears(2)\n * Subtracting 10 years\n * => myDate.addYears(-10)\n * */\n var addYears = function(date, y) {\n var copiedDate = new Date(date.getTime());\n copiedDate.setFullYear(copiedDate.getFullYear() + y);\n return copiedDate;\n }\n\n var _proto = {\n setCulture : setCulture,\n format : format,\n countDaysTo : countDaysTo,\n getDaysTo : getDaysTo,\n getDaysInMonth : getDaysInMonth,\n getQuarter : getQuarter,\n getHalfYear : getHalfYear,\n getWeek : getWeek,\n addHours : addHours,\n addDays : addDays,\n addYears : addYears\n };\n \n return _proto\n\n};\n\nif ( ( typeof(module) !== 'undefined' ) && module.exports ) {\n // Publish as node.js module\n module.exports = DateFormatHelper\n} else if ( typeof(define) === 'function' && define.amd) {\n // Publish as AMD module\n define( 'helpers/dateFormat',[],function() { return DateFormatHelper })\n};\n",
37
+ "/*\n * This file is part of the gina package.\n * Copyright (c) 2009-2023 Rhinostone <contact@gina.io>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n/**\n * Credits & thanks to Steven Levithan :)\n * http://blog.stevenlevithan.com/archives/date-time-format\n * \n * \n * \n * Original Copyrights\n * Date Format 1.2.3\n * (c) 2007-2009 Steven Levithan <stevenlevithan.com>\n * MIT license\n *\n * Includes enhancements by Scott Trenda <scott.trenda.net>\n * and Kris Kowal <cixar.com/~kris.kowal/>\n *\n * Accepts a date, a mask, or a date and a mask.\n * Returns a formatted version of the given date.\n * The date defaults to the current date/time.\n * The mask defaults to dateFormat.masks.default.\n *\n * @param {string} date\n * @param {string} mask\n */\nfunction DateFormatHelper() {\n \n var isGFFCtx = ( ( typeof(module) !== 'undefined' ) && module.exports ) ? false : true;\n\n var merge = (isGFFCtx) ? require('utils/merge') : require('./../lib/merge');\n \n // if ( typeof(define) === 'function' && define.amd ) {\n // var Date = this.Date;\n // }\n \n var self = {};\n // language-country\n self.culture = 'en-US'; // by default\n self.lang = 'en'; // by default\n\n self.masks = {\n // i18n\n \"default\": \"ddd mmm dd yyyy HH:MM:ss\",\n shortDate: \"m/d/yy\",\n shortDate2: \"mm/dd/yyyy\",\n mediumDate: \"mmm d, yyyy\",\n longDate: \"mmmm d, yyyy\",\n fullDate: \"dddd, mmmm d, yyyy\",\n // common\n cookieDate: \"GMT:ddd, dd mmm yyyy HH:MM:ss\",\n logger: \"[yyyy mmm dd HH:MM:ss]\",\n shortTime: \"h:MM TT\",\n shortTime2: \"h:MM\",\n mediumTime: \"h:MM:ss TT\",\n mediumTime2: \"h:MM:ss\",\n longTime: \"h:MM:ss TT Z\",\n longTime2: \"h:MM:ss TT\",\n concatenatedDate: \"yyyymmdd\",\n isoDate: \"yyyy-mm-dd\",\n isoTime: \"HH:MM:ss\",\n shortIsoTime: \"HH:MM\",\n longIsoTime: \"HH:MM:ss TT\",\n isoDateTime: \"yyyy-mm-dd'T'HH:MM:ss\",\n isoUtcDateTime: \"UTC:yyyy-mm-dd'T'HH:MM:ss'Z'\"\n };\n \n self.i18n = {\n 'en': {\n dayNames: [\n \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\",\n \"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"\n ],\n monthNames: [\n \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n \"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"\n ],\n masks: {\n \"default\": \"ddd mmm dd yyyy HH:MM:ss\",\n shortDate: \"m/d/yy\",\n shortDate2: \"mm/dd/yyyy\",\n mediumDate: \"mmm d, yyyy\",\n longDate: \"mmmm d, yyyy\",\n fullDate: \"dddd, mmmm d, yyyy\"\n }\n },\n 'fr': {\n dayNames: [\n \"dim\", \"lun\", \"mar\", \"mer\", \"jeu\", \"ven\", \"sam\",\n \"dimanche\", \"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\", \"samedi\"\n ],\n monthNames: [\n \"Jan\", \"Fév\", \"Mar\", \"Avr\", \"Mai\", \"Jui\", \"Juil\", \"Aoû\", \"Sep\", \"Oct\", \"Nov\", \"Déc\",\n \"Janvier\", \"Février\", \"Mars\", \"Avril\", \"Mai\", \"Juin\", \"Juillet\", \"Août\", \"Septembre\", \"Octobre\", \"Novembre\", \"Décembre\"\n ],\n masks: {\n \"default\": \"ddd mmm dd yyyy HH:MM:ss\",\n shortDate: \"d/m/yy\",\n shortDate2: \"dd/mm/yyyy\",\n mediumDate: \"d mmm, yyyy\",\n longDate: \"d mmmm, yyyy\",\n fullDate: \"dddd, d mmmm, yyyy\"\n }\n }\n };\n \n /**\n * \n * @param {string} culture (5 chars) | lang (2 chars) \n */\n var setCulture = function(date, culture) {\n if (/\\-/.test(culture) ) {\n self.culture = culture;\n self.lang = culture.split(/\\-/)[0];\n } else {\n self.lang = culture\n } \n \n return this\n }\n\n var format = function(date, mask, utc) {\n var dF = self\n , i18n = dF.i18n[dF.lang] || dF.i18n['en']\n , masksList = merge(i18n.masks, dF.masks)\n ;\n \n if ( typeof(dF.i18n[dF.culture]) != 'undefined' ) {\n i18n = dF.i18n[dF.culture];\n if ( typeof(dF.i18n[dF.culture].mask) != 'undefined' ) {\n masksList = merge(i18n.masks, dF.masks)\n }\n }\n\n var\ttoken = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\\1?|[LloSZ]|\"[^\"]*\"|'[^']*'/g,\n timezone = /\\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\\d{4})?)\\b/g,\n timezoneClip = /[^-+\\dA-Z]/g,\n pad = function (val, len) {\n val = String(val);\n len = len || 2;\n while (val.length < len) val = \"0\" + val;\n return val;\n };\n\n // You can't provide utc if you skip other args (use the \"UTC:\" mask prefix)\n if (arguments.length == 1 && Object.prototype.toString.call(date) == \"[object String]\" && !/\\d/.test(date)) {\n mask = date;\n date = undefined;\n }\n\n // Passing date through Date applies Date.parse, if necessary\n date = date ? new Date(date) : new Date();\n if (isNaN(date)) throw SyntaxError(\"invalid date\");\n\n mask = String(masksList[mask] || mask || masksList[\"default\"]);\n\n // Allow setting the utc argument via the mask\n if (mask.slice(0, 4) == \"UTC:\") {\n mask = mask.slice(4);\n utc = true;\n }\n\n var\t_ = utc ? \"getUTC\" : \"get\",\n d = date[_ + \"Date\"](),\n D = date[_ + \"Day\"](),\n m = date[_ + \"Month\"](),\n y = date[_ + \"FullYear\"](),\n H = date[_ + \"Hours\"](),\n M = date[_ + \"Minutes\"](),\n s = date[_ + \"Seconds\"](),\n L = date[_ + \"Milliseconds\"](),\n o = utc ? 0 : date.getTimezoneOffset(),\n flags = {\n d: d,\n dd: pad(d),\n ddd: i18n.dayNames[D],\n dddd: i18n.dayNames[D + 7],\n m: m + 1,\n mm: pad(m + 1),\n mmm: i18n.monthNames[m],\n mmmm: i18n.monthNames[m + 12],\n yy: String(y).slice(2),\n yyyy: y,\n h: H % 12 || 12,\n hh: pad(H % 12 || 12),\n H: H,\n HH: pad(H),\n M: M,\n MM: pad(M),\n s: s,\n ss: pad(s),\n l: pad(L, 3),\n L: pad(L > 99 ? Math.round(L / 10) : L),\n t: H < 12 ? \"a\" : \"p\",\n tt: H < 12 ? \"am\" : \"pm\",\n T: H < 12 ? \"A\" : \"P\",\n TT: H < 12 ? \"AM\" : \"PM\",\n Z: utc ? \"UTC\" : (String(date).match(timezone) || [\"\"]).pop().replace(timezoneClip, \"\"),\n o: (o > 0 ? \"-\" : \"+\") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),\n S: [\"th\", \"st\", \"nd\", \"rd\"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]\n };\n\n\n\n return mask.replace(token, function ($0) {\n return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);\n });\n }\n\n /**\n * Get mask name from a given format\n *\n * @param {string} format\n *\n * @return {string} maskName\n * */\n // var getMaskNameFromFormat = function (format) {\n\n // var name = \"default\";\n\n // for (var f in self.masks) {\n // if ( self.masks[f] === format )\n // return f\n // }\n\n // return name\n // }\n\n\n /**\n * Count days from the current date to another\n *\n * TODO - add a closure to `ignoreWeekend()` based on Lib::Validator\n * TODO - add a closure to `ignoreFromList(array)` based on Lib::Validator\n *\n * @param {object} dateTo\n * @return {number} count\n * */\n var countDaysTo = function(date, dateTo) {\n\n if ( dateTo instanceof Date) {\n // The number of milliseconds in one day\n var oneDay = 1000 * 60 * 60 * 24\n\n // Convert both dates to milliseconds\n var date1Ms = date.getTime()\n var date2Ms = dateTo.getTime()\n\n // Calculate the difference in milliseconds\n var count = Math.abs(date1Ms - date2Ms)\n\n // Convert back to days and return\n return Math.round(count/oneDay);\n } else {\n throw new Error('dateTo is not instance of Date() !')\n }\n }\n\n /**\n * Will give an array of dates between the current date to a targeted date\n *\n * TODO - add a closure to `ignoreWeekend()` based on Utils::Validator\n * TODO - add a closure to `ignoreFromList(array)` based on Utils::Validator\n *\n * @param {object} dateTo\n * @param {string} [ mask ]\n *\n * @return {array} dates\n * */\n var getDaysTo = function(date, dateTo, mask) {\n\n if ( dateTo instanceof Date) {\n var count = countDaysTo(date, dateTo)\n , month = date.getMonth()\n , year = date.getFullYear()\n , day = date.getDate() + 1\n , dateObj = new Date(year, month, day)\n , days = []\n , i = 0;\n\n for (; i < count; ++i) {\n if ( typeof(mask) != 'undefined' ) {\n days.push(new Date(dateObj).format(mask));\n } else {\n days.push(new Date(dateObj));\n }\n\n dateObj.setDate(dateObj.getDate() + 1);\n }\n\n return days || [];\n } else {\n throw new Error('dateTo is not instance of Date() !')\n }\n }\n\n var getDaysInMonth = function(date) {\n var month = date.getMonth();\n var year = date.getFullYear();\n var dateObj = new Date(year, month, 1);\n var days = [];\n while (dateObj.getMonth() === month) {\n days.push(new Date(dateObj));\n dateObj.setDate(dateObj.getDate() + 1);\n }\n return days;\n }\n \n \n /**\n * getQuarter\n * Get quarter number\n * To test : https://planetcalc.com/1252/\n * Based on fiscal year- See.: https://en.wikipedia.org/wiki/Fiscal_year\n * \n * TODO - Complete fiscalCodes\n * \n * @param {object} [date] if not defined, will take today's value\n * @param {string} [code] - us|eu\n * \n * @return {number} quarterNumber - 1 to 4\n */\n var fiscalCodes = ['us', 'eu', 'corporate'];\n var getQuarter = function(date, code) {\n if (\n arguments.length == 1 \n && typeof(arguments[0]) == 'string'\n ) {\n if ( fiscalCodes.indexOf(arguments[0].toLowerCase()) < 0 ) {\n throw new Error('Quarter '+ arguments[0] +' code not supported !');\n }\n date = new Date();\n code = arguments[0]\n }\n if ( typeof(date) == 'undefined' ) {\n date = new Date();\n }\n if ( typeof(code) == 'undefined') {\n code = 'corporate';\n }\n \n code = code.toLowerCase();\n var q = [1,2,3,4]; // EU & corporates by default\n switch (code) {\n case 'us':\n q = [4,1,2,3];\n break;\n \n case 'corportate':\n case 'eu':\n q = [1,2,3,4]\n break;\n default:\n // EU & corporates by default\n q = [1,2,3,4];\n break;\n }\n \n return q[Math.floor(date.getMonth() / 3)];\n }\n \n /**\n * getHalfYear\n * \n * Based on fiscal year- See.: https://en.wikipedia.org/wiki/Fiscal_year\n * \n * @param {object} date \n * @param {string} code\n * \n * @return halfYear number - 1 to 2\n */\n var getHalfYear = function(date, code) {\n if (\n arguments.length == 1 \n && typeof(arguments[0]) == 'string'\n ) {\n if ( fiscalCodes.indexOf(arguments[0].toLowerCase()) < 0 ) {\n throw new Error('Quarter '+ arguments[0] +' code not supported !');\n }\n date = new Date();\n code = arguments[0]\n }\n if ( typeof(date) == 'undefined' ) {\n date = new Date();\n }\n if ( typeof(code) == 'undefined') {\n code = 'corporate';\n }\n \n code = code.toLowerCase();\n \n return (date.getQuarter(code) <=2 ) ? 1 : 2;\n }\n \n /**\n * getWeekISO8601\n * Get week number\n * ISO 8601\n * To test : https://planetcalc.com/1252/\n * \n * @param {object} [date] if not defined, will take today's value\n * \n * @return {number} weekNumber\n */\n var getWeekISO8601 = function(date) {\n // Copy date so don't modify original\n d = new Date(date.getFullYear(), date.getMonth(), date.getDate()); \n // Make Sunday's day number 7\n var dayNum = d.getDay() || 7;\n d.setDate(d.getDate() + 4 - dayNum);\n var yearStart = new Date(Date.parse(d.getFullYear(),0,1));\n \n return Math.ceil((((d - yearStart) / 86400000) + 1)/7)\n }\n \n /**\n * getWeek\n * Get week number\n * To test : https://planetcalc.com/1252/\n * \n * @param {object} [date] if not defined, will take today's value\n * \n * @return {number} weekNumber - 1 to 53\n */\n var getWeek = function(date, standardMethod) {\n if ( typeof(date) == 'undefined' ) {\n date = new Date();\n }\n if ( typeof(standardMethod) == 'undefined') {\n standardMethod = 'ISO 8601';\n }\n \n standardMethod = standardMethod.replace(/\\s+/g, '').toLowerCase();\n switch (standardMethod) {\n case 'corporate':\n case 'eu':\n case 'iso8601':\n return getWeekISO8601(date)\n \n default:\n return getWeekISO8601(date)\n }\n }\n\n /**\n * Add or subtract hours\n * Adding 2 hours\n * => myDate.addHours(2)\n * Subtracting 10 hours\n * => myDate.addHours(-10)\n * */\n var addHours = function(date, h) {\n var copiedDate = new Date(date.getTime());\n copiedDate.setHours(copiedDate.getHours() + h);\n return copiedDate;\n }\n\n\n /**\n * Add or subtract days\n * Adding 2 days\n * => myDate.addDays(2)\n * Subtracting 10 days\n * => myDate.addDays(-10)\n * */\n var addDays = function(date, d) {\n var copiedDate = new Date(date.getTime());\n copiedDate.setHours(copiedDate.getHours() + d * 24);\n return copiedDate;\n }\n\n /**\n * Add or subtract years\n * Adding 2 days\n * => myDate.addYears(2)\n * Subtracting 10 years\n * => myDate.addYears(-10)\n * */\n var addYears = function(date, y) {\n var copiedDate = new Date(date.getTime());\n copiedDate.setFullYear(copiedDate.getFullYear() + y);\n return copiedDate;\n }\n\n var _proto = {\n setCulture : setCulture,\n format : format,\n countDaysTo : countDaysTo,\n getDaysTo : getDaysTo,\n getDaysInMonth : getDaysInMonth,\n getQuarter : getQuarter,\n getHalfYear : getHalfYear,\n getWeek : getWeek,\n addHours : addHours,\n addDays : addDays,\n addYears : addYears\n };\n \n return _proto\n\n};\n\nif ( ( typeof(module) !== 'undefined' ) && module.exports ) {\n // Publish as node.js module\n module.exports = DateFormatHelper\n} else if ( typeof(define) === 'function' && define.amd) {\n // Publish as AMD module\n define( 'helpers/dateFormat',[],function() { return DateFormatHelper })\n};\n",
38
38
  "/*! jQuery v1.12.4 | (c) jQuery Foundation | jquery.org/license */\n!function(a,b){\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error(\"jQuery requires a window with a document\");return b(a)}:b(a)}(\"undefined\"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m=\"1.12.4\",n=function(a,b){return new n.fn.init(a,b)},o=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,p=/^-ms-/,q=/-([\\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:\"\",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for(\"boolean\"==typeof g&&(j=g,g=arguments[h]||{},h++),\"object\"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:\"jQuery\"+(m+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return\"function\"===n.type(a)},isArray:Array.isArray||function(a){return\"array\"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||\"object\"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,\"constructor\")&&!k.call(a.constructor.prototype,\"isPrototypeOf\"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+\"\":\"object\"==typeof a||\"function\"==typeof a?i[j.call(a)]||\"object\":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,\"ms-\").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?\"\":(a+\"\").replace(o,\"\")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,\"string\"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return\"string\"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),\"function\"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(a,b){i[\"[object \"+b+\"]\"]=b.toLowerCase()});function s(a){var b=!!a&&\"length\"in a&&a.length,c=n.type(a);return\"function\"===c||n.isWindow(a)?!1:\"array\"===c||0===b||\"number\"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u=\"sizzle\"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",L=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",M=\"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",N=\"\\\\[\"+L+\"*(\"+M+\")(?:\"+L+\"*([*^$|!~]?=)\"+L+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+M+\"))|)\"+L+\"*\\\\]\",O=\":(\"+M+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+N+\")*)|.*)\\\\)|)\",P=new RegExp(L+\"+\",\"g\"),Q=new RegExp(\"^\"+L+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+L+\"+$\",\"g\"),R=new RegExp(\"^\"+L+\"*,\"+L+\"*\"),S=new RegExp(\"^\"+L+\"*([>+~]|\"+L+\")\"+L+\"*\"),T=new RegExp(\"=\"+L+\"*([^\\\\]'\\\"]*?)\"+L+\"*\\\\]\",\"g\"),U=new RegExp(O),V=new RegExp(\"^\"+M+\"$\"),W={ID:new RegExp(\"^#(\"+M+\")\"),CLASS:new RegExp(\"^\\\\.(\"+M+\")\"),TAG:new RegExp(\"^(\"+M+\"|[*])\"),ATTR:new RegExp(\"^\"+N),PSEUDO:new RegExp(\"^\"+O),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+L+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+L+\"*(?:([+-]|)\"+L+\"*(\\\\d+)|))\"+L+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+K+\")$\",\"i\"),needsContext:new RegExp(\"^\"+L+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+L+\"*((?:-\\\\d)?\\\\d*)\"+L+\"*\\\\)|)(?=[^-]|$)\",\"i\")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\\d$/i,Z=/^[^{]+\\{\\s*\\[native \\w/,$=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,_=/[+~]/,aa=/'|\\\\/g,ba=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+L+\"?|(\"+L+\")|.)\",\"ig\"),ca=function(a,b,c){var d=\"0x\"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],\"string\"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+\" \"]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if(\"object\"!==b.nodeName.toLowerCase()){(k=b.getAttribute(\"id\"))?k=k.replace(aa,\"\\\\$&\"):b.setAttribute(\"id\",k=u),r=g(a),h=r.length,l=V.test(k)?\"#\"+k:\"[id='\"+k+\"']\";while(h--)r[h]=l+\" \"+qa(r[h]);s=r.join(\",\"),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute(\"id\")}}}return i(a.replace(Q,\"$1\"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+\" \")>d.cacheLength&&delete b[a.shift()],b[c+\" \"]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement(\"div\");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split(\"|\"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return\"input\"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return(\"input\"===c||\"button\"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&\"undefined\"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?\"HTML\"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener(\"unload\",da,!1):e.attachEvent&&e.attachEvent(\"onunload\",da)),c.attributes=ia(function(a){return a.className=\"i\",!a.getAttribute(\"className\")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment(\"\")),!a.getElementsByTagName(\"*\").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(\"undefined\"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute(\"id\")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c=\"undefined\"!=typeof a.getAttributeNode&&a.getAttributeNode(\"id\");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return\"undefined\"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if(\"*\"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return\"undefined\"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML=\"<a id='\"+u+\"'></a><select id='\"+u+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",a.querySelectorAll(\"[msallowcapture^='']\").length&&q.push(\"[*^$]=\"+L+\"*(?:''|\\\"\\\")\"),a.querySelectorAll(\"[selected]\").length||q.push(\"\\\\[\"+L+\"*(?:value|\"+K+\")\"),a.querySelectorAll(\"[id~=\"+u+\"-]\").length||q.push(\"~=\"),a.querySelectorAll(\":checked\").length||q.push(\":checked\"),a.querySelectorAll(\"a#\"+u+\"+*\").length||q.push(\".#.+[+~]\")}),ia(function(a){var b=n.createElement(\"input\");b.setAttribute(\"type\",\"hidden\"),a.appendChild(b).setAttribute(\"name\",\"D\"),a.querySelectorAll(\"[name=d]\").length&&q.push(\"name\"+L+\"*[*^$|!~]?=\"),a.querySelectorAll(\":enabled\").length||q.push(\":enabled\",\":disabled\"),a.querySelectorAll(\"*,:x\"),q.push(\",.*:\")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,\"div\"),s.call(a,\"[s!='']:x\"),r.push(\"!=\",O)}),q=q.length&&new RegExp(q.join(\"|\")),r=r.length&&new RegExp(r.join(\"|\")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,\"='$1']\"),c.matchesSelector&&p&&!A[b+\" \"]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error(\"Syntax error, unrecognized expression: \"+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c=\"\",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if(\"string\"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||\"\").replace(ba,ca),\"~=\"===a[2]&&(a[3]=\" \"+a[3]+\" \"),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),\"nth\"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*(\"even\"===a[3]||\"odd\"===a[3])),a[5]=+(a[7]+a[8]||\"odd\"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||\"\":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(\")\",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return\"*\"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+\" \"];return b||(b=new RegExp(\"(^|\"+L+\")\"+a+\"(\"+L+\"|$)\"))&&y(a,function(a){return b.test(\"string\"==typeof a.className&&a.className||\"undefined\"!=typeof a.getAttribute&&a.getAttribute(\"class\")||\"\")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?\"!=\"===b:b?(e+=\"\",\"=\"===b?e===c:\"!=\"===b?e!==c:\"^=\"===b?c&&0===e.indexOf(c):\"*=\"===b?c&&e.indexOf(c)>-1:\"$=\"===b?c&&e.slice(-c.length)===c:\"~=\"===b?(\" \"+e.replace(P,\" \")+\" \").indexOf(c)>-1:\"|=\"===b?e===c||e.slice(0,c.length+1)===c+\"-\":!1):!0}},CHILD:function(a,b,c,d,e){var f=\"nth\"!==a.slice(0,3),g=\"last\"!==a.slice(-4),h=\"of-type\"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?\"nextSibling\":\"previousSibling\",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p=\"only\"===a&&!o&&\"nextSibling\"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error(\"unsupported pseudo: \"+a);return e[u]?e(b):e.length>1?(c=[a,a,\"\",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,\"$1\"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||\"\")||fa.error(\"unsupported lang: \"+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute(\"xml:lang\")||b.getAttribute(\"lang\"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+\"-\");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return\"input\"===b&&!!a.checked||\"option\"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return\"input\"===b&&\"button\"===a.type||\"button\"===b},text:function(a){var b;return\"input\"===a.nodeName.toLowerCase()&&\"text\"===a.type&&(null==(b=a.getAttribute(\"type\"))||\"text\"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=la(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=ma(b);function pa(){}pa.prototype=d.filters=d.pseudos,d.setFilters=new pa,g=fa.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+\" \"];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=R.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=S.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(Q,\" \")}),h=h.slice(c.length));for(g in d.filter)!(e=W[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fa.error(a):z(a,i).slice(0)};function qa(a){for(var b=0,c=a.length,d=\"\";c>b;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&\"parentNode\"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||\"*\",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[\" \"],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:\" \"===a[i-2].type?\"*\":\"\"})).replace(Q,\"$1\"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s=\"0\",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG(\"*\",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+\" \"];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n=\"function\"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&\"ID\"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split(\"\").sort(B).join(\"\")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement(\"div\"))}),ia(function(a){return a.innerHTML=\"<a href='#'></a>\",\"#\"===a.firstChild.getAttribute(\"href\")})||ja(\"type|href|height|width\",function(a,b,c){return c?void 0:a.getAttribute(b,\"type\"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML=\"<input/>\",a.firstChild.setAttribute(\"value\",\"\"),\"\"===a.firstChild.getAttribute(\"value\")})||ja(\"value\",function(a,b,c){return c||\"input\"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute(\"disabled\")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[\":\"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\\w-]+)\\s*\\/?>(?:<\\/\\1>|)$/,y=/^.[^:#\\[\\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if(\"string\"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=\":not(\"+a+\")\"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if(\"string\"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+\" \"+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,\"string\"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,\"string\"==typeof a){if(e=\"<\"===a.charAt(0)&&\">\"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?\"undefined\"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||\"string\"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?\"string\"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,\"parentNode\")},parentsUntil:function(a,b,c){return u(a,\"parentNode\",c)},next:function(a){return F(a,\"nextSibling\")},prev:function(a){return F(a,\"previousSibling\")},nextAll:function(a){return u(a,\"nextSibling\")},prevAll:function(a){return u(a,\"previousSibling\")},nextUntil:function(a,b,c){return u(a,\"nextSibling\",c)},prevUntil:function(a,b,c){return u(a,\"previousSibling\",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,\"iframe\")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return\"Until\"!==a.slice(-5)&&(d=c),d&&\"string\"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a=\"string\"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:\"\")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){n.each(b,function(b,c){n.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&\"string\"!==n.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return n.each(arguments,function(a,b){var c;while((c=n.inArray(b,f,c))>-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c=\"\",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[[\"resolve\",\"done\",n.Callbacks(\"once memory\"),\"resolved\"],[\"reject\",\"fail\",n.Callbacks(\"once memory\"),\"rejected\"],[\"notify\",\"progress\",n.Callbacks(\"memory\")]],c=\"pending\",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+\"With\"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+\"With\"](this===e?d:this,arguments),this},e[f[0]+\"With\"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler(\"ready\"),n(d).off(\"ready\"))))}});function J(){d.addEventListener?(d.removeEventListener(\"DOMContentLoaded\",K),a.removeEventListener(\"load\",K)):(d.detachEvent(\"onreadystatechange\",K),a.detachEvent(\"onload\",K))}function K(){(d.addEventListener||\"load\"===a.event.type||\"complete\"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),\"complete\"===d.readyState||\"loading\"!==d.readyState&&!d.documentElement.doScroll)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener(\"DOMContentLoaded\",K),a.addEventListener(\"load\",K);else{d.attachEvent(\"onreadystatechange\",K),a.attachEvent(\"onload\",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll(\"left\")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst=\"0\"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName(\"body\")[0],c&&c.style&&(b=d.createElement(\"div\"),e=d.createElement(\"div\"),e.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",c.appendChild(e).appendChild(b),\"undefined\"!=typeof b.style.zoom&&(b.style.cssText=\"display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1\",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement(\"div\");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+\" \").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute(\"classid\")===b},N=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d=\"data-\"+b.replace(O,\"-$1\").toLowerCase();if(c=a.getAttribute(d),\"string\"==typeof c){try{c=\"true\"===c?!0:\"false\"===c?!1:\"null\"===c?null:+c+\"\"===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0;\n}return c}function Q(a){var b;for(b in a)if((\"data\"!==b||!n.isEmptyObject(a[b]))&&\"toJSON\"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||\"string\"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),\"object\"!=typeof b&&\"function\"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),\"string\"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(\" \")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{\"applet \":!0,\"embed \":!0,\"object \":\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,\"parsedAttrs\"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf(\"data-\")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,\"parsedAttrs\",!0)}return e}return\"object\"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||\"fx\")+\"queue\",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||\"fx\";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};\"inprogress\"===e&&(e=c.shift(),d--),e&&(\"fx\"===b&&c.unshift(\"inprogress\"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+\"queueHooks\";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks(\"once memory\").add(function(){n._removeData(a,b+\"queue\"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return\"string\"!=typeof a&&(b=a,a=\"fx\",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),\"fx\"===a&&\"inprogress\"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||\"fx\",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};\"string\"!=typeof a&&(b=a,a=void 0),a=a||\"fx\";while(g--)c=n._data(f[g],a+\"queueHooks\"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}}),function(){var a;l.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,e;return c=d.getElementsByTagName(\"body\")[0],c&&c.style?(b=d.createElement(\"div\"),e=d.createElement(\"div\"),e.style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",c.appendChild(e).appendChild(b),\"undefined\"!=typeof b.style.zoom&&(b.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1\",b.appendChild(d.createElement(\"div\")).style.width=\"5px\",a=3!==b.offsetWidth),c.removeChild(e),a):void 0}}();var T=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,U=new RegExp(\"^(?:([+-])=|)(\"+T+\")([a-z%]*)$\",\"i\"),V=[\"Top\",\"Right\",\"Bottom\",\"Left\"],W=function(a,b){return a=b||a,\"none\"===n.css(a,\"display\")||!n.contains(a.ownerDocument,a)};function X(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return n.css(a,b,\"\")},i=h(),j=c&&c[3]||(n.cssNumber[b]?\"\":\"px\"),k=(n.cssNumber[b]||\"px\"!==j&&+i)&&U.exec(n.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||\".5\",k/=f,n.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var Y=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if(\"object\"===n.type(c)){e=!0;for(h in c)Y(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\\w:-]+)/,_=/^$|\\/(?:java|ecma)script/i,aa=/^\\s+/,ba=\"abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video\";function ca(a){var b=ba.split(\"|\"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement(\"div\"),b=d.createDocumentFragment(),c=d.createElement(\"input\");a.innerHTML=\" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName(\"tbody\").length,l.htmlSerialize=!!a.getElementsByTagName(\"link\").length,l.html5Clone=\"<:nav></:nav>\"!==d.createElement(\"nav\").cloneNode(!0).outerHTML,c.type=\"checkbox\",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML=\"<textarea>x</textarea>\",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement(\"input\"),c.setAttribute(\"type\",\"radio\"),c.setAttribute(\"checked\",\"checked\"),c.setAttribute(\"name\",\"t\"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],area:[1,\"<map>\",\"</map>\"],param:[1,\"<object>\",\"</object>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:l.htmlSerialize?[0,\"\",\"\"]:[1,\"X<div>\",\"</div>\"]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f=\"undefined\"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||\"*\"):\"undefined\"!=typeof a.querySelectorAll?a.querySelectorAll(b||\"*\"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,\"globalEval\",!b||n._data(b[d],\"globalEval\"))}var ga=/<|&#?\\w+;/,ha=/<tbody/i;function ia(a){Z.test(a.type)&&(a.defaultChecked=a.checked)}function ja(a,b,c,d,e){for(var f,g,h,i,j,k,m,o=a.length,p=ca(b),q=[],r=0;o>r;r++)if(g=a[r],g||0===g)if(\"object\"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement(\"div\")),j=($.exec(g)||[\"\",\"\"])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g=\"table\"!==j||ha.test(g)?\"<table>\"!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],\"tbody\")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent=\"\";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,\"input\"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),\"script\"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||\"\")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement(\"div\");for(b in{submit:!0,change:!0,focusin:!0})c=\"on\"+b,(l[b]=c in a)||(e.setAttribute(c,\"t\"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if(\"object\"==typeof b){\"string\"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&(\"string\"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return\"undefined\"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||\"\").match(G)||[\"\"],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||\"\").split(\".\").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(\".\")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent(\"on\"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||\"\").match(G)||[\"\"],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||\"\").split(\".\").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp(\"(^|\\\\.)\"+p.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&(\"**\"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,\"events\"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,\"type\")?b.type:b,r=k.call(b,\"namespace\")?b.namespace.split(\".\"):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(\".\")>-1&&(r=q.split(\".\"),q=r.shift(),r.sort()),h=q.indexOf(\":\")<0&&\"on\"+q,b=b[n.expando]?b:new n.Event(q,\"object\"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join(\".\"),b.rnamespace=b.namespace?new RegExp(\"(^|\\\\.)\"+r.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,\"events\")||{})[b.type]&&n._data(i,\"handle\"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,\"events\")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(\"click\"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||\"click\"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+\" \",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[n.expando])return a;var b,c,e,f=a.type,g=a,h=this.fixHooks[f];h||(this.fixHooks[f]=h=ma.test(f)?this.mouseHooks:la.test(f)?this.keyHooks:{}),e=h.props?this.props.concat(h.props):this.props,a=new n.Event(g),b=e.length;while(b--)c=e[b],a[c]=g[c];return a.target||(a.target=g.srcElement||d),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,h.filter?h.filter(a,g):a},props:\"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),fixHooks:{},keyHooks:{props:\"char charCode key keyCode\".split(\" \"),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:\"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),filter:function(a,b){var c,e,f,g=b.button,h=b.fromElement;return null==a.pageX&&null!=b.clientX&&(e=a.target.ownerDocument||d,f=e.documentElement,c=e.body,a.pageX=b.clientX+(f&&f.scrollLeft||c&&c.scrollLeft||0)-(f&&f.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(f&&f.scrollTop||c&&c.scrollTop||0)-(f&&f.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&h&&(a.relatedTarget=h===a.target?b.toElement:h),a.which||void 0===g||(a.which=1&g?1:2&g?3:4&g?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==ra()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:\"focusin\"},blur:{trigger:function(){return this===ra()&&this.blur?(this.blur(),!1):void 0},delegateType:\"focusout\"},click:{trigger:function(){return n.nodeName(this,\"input\")&&\"checkbox\"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,\"a\")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c){var d=n.extend(new n.Event,c,{type:a,isSimulated:!0});n.event.trigger(d,null,b),d.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=d.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)}:function(a,b,c){var d=\"on\"+b;a.detachEvent&&(\"undefined\"==typeof a[d]&&(a[d]=null),a.detachEvent(d,c))},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?pa:qa):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={constructor:n.Event,isDefaultPrevented:qa,isPropagationStopped:qa,isImmediatePropagationStopped:qa,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=pa,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=pa,a&&!this.isSimulated&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=pa,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||n.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.submit||(n.event.special.submit={setup:function(){return n.nodeName(this,\"form\")?!1:void n.event.add(this,\"click._submit keypress._submit\",function(a){var b=a.target,c=n.nodeName(b,\"input\")||n.nodeName(b,\"button\")?n.prop(b,\"form\"):void 0;c&&!n._data(c,\"submit\")&&(n.event.add(c,\"submit._submit\",function(a){a._submitBubble=!0}),n._data(c,\"submit\",!0))})},postDispatch:function(a){a._submitBubble&&(delete a._submitBubble,this.parentNode&&!a.isTrigger&&n.event.simulate(\"submit\",this.parentNode,a))},teardown:function(){return n.nodeName(this,\"form\")?!1:void n.event.remove(this,\"._submit\")}}),l.change||(n.event.special.change={setup:function(){return ka.test(this.nodeName)?(\"checkbox\"!==this.type&&\"radio\"!==this.type||(n.event.add(this,\"propertychange._change\",function(a){\"checked\"===a.originalEvent.propertyName&&(this._justChanged=!0)}),n.event.add(this,\"click._change\",function(a){this._justChanged&&!a.isTrigger&&(this._justChanged=!1),n.event.simulate(\"change\",this,a)})),!1):void n.event.add(this,\"beforeactivate._change\",function(a){var b=a.target;ka.test(b.nodeName)&&!n._data(b,\"change\")&&(n.event.add(b,\"change._change\",function(a){!this.parentNode||a.isSimulated||a.isTrigger||n.event.simulate(\"change\",this.parentNode,a)}),n._data(b,\"change\",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||\"radio\"!==b.type&&\"checkbox\"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return n.event.remove(this,\"._change\"),!ka.test(this.nodeName)}}),l.focusin||n.each({focus:\"focusin\",blur:\"focusout\"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a))};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=n._data(d,b);e||d.addEventListener(a,c,!0),n._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=n._data(d,b)-1;e?n._data(d,b,e):(d.removeEventListener(a,c,!0),n._removeData(d,b))}}}),n.fn.extend({on:function(a,b,c,d){return sa(this,a,b,c,d)},one:function(a,b,c,d){return sa(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+\".\"+d.namespace:d.origType,d.selector,d.handler),this;if(\"object\"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&\"function\"!=typeof b||(c=b,b=void 0),c===!1&&(c=qa),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ta=/ jQuery\\d+=\"(?:null|\\d+)\"/g,ua=new RegExp(\"<(?:\"+ba+\")[\\\\s/>]\",\"i\"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:-]+)[^>]*)\\/>/gi,wa=/<script|<style|<link/i,xa=/checked\\s*(?:[^=]|=\\s*.checked.)/i,ya=/^true\\/(.*)/,za=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,Aa=ca(d),Ba=Aa.appendChild(d.createElement(\"div\"));function Ca(a,b){return n.nodeName(a,\"table\")&&n.nodeName(11!==b.nodeType?b:b.firstChild,\"tr\")?a.getElementsByTagName(\"tbody\")[0]||a.appendChild(a.ownerDocument.createElement(\"tbody\")):a}function Da(a){return a.type=(null!==n.find.attr(a,\"type\"))+\"/\"+a.type,a}function Ea(a){var b=ya.exec(a.type);return b?a.type=b[1]:a.removeAttribute(\"type\"),a}function Fa(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Ga(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}\"script\"===c&&b.text!==a.text?(Da(b).text=a.text,Ea(b)):\"object\"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):\"input\"===c&&Z.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):\"option\"===c?b.defaultSelected=b.selected=a.defaultSelected:\"input\"!==c&&\"textarea\"!==c||(b.defaultValue=a.defaultValue)}}function Ha(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&\"string\"==typeof q&&!l.checkClone&&xa.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(o&&(k=ja(b,a[0].ownerDocument,!1,a,d),e=k.firstChild,1===k.childNodes.length&&(k=e),e||d)){for(i=n.map(ea(k,\"script\"),Da),h=i.length;o>m;m++)g=k,m!==p&&(g=n.clone(g,!0,!0),h&&n.merge(i,ea(g,\"script\"))),c.call(a[m],g,m);if(h)for(j=i[i.length-1].ownerDocument,n.map(i,Ea),m=0;h>m;m++)g=i[m],_.test(g.type||\"\")&&!n._data(g,\"globalEval\")&&n.contains(j,g)&&(g.src?n._evalUrl&&n._evalUrl(g.src):n.globalEval((g.text||g.textContent||g.innerHTML||\"\").replace(za,\"\")));k=e=null}return a}function Ia(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(ea(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&fa(ea(d,\"script\")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(va,\"<$1></$2>\")},clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!ua.test(\"<\"+a.nodeName+\">\")?f=a.cloneNode(!0):(Ba.innerHTML=a.outerHTML,Ba.removeChild(f=Ba.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=ea(f),h=ea(a),g=0;null!=(e=h[g]);++g)d[g]&&Ga(e,d[g]);if(b)if(c)for(h=h||ea(a),d=d||ea(f),g=0;null!=(e=h[g]);g++)Fa(e,d[g]);else Fa(a,f);return d=ea(f,\"script\"),d.length>0&&fa(d,!i&&ea(a,\"script\")),d=h=e=null,f},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.attributes,m=n.event.special;null!=(d=a[h]);h++)if((b||M(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k||\"undefined\"==typeof d.removeAttribute?d[i]=void 0:d.removeAttribute(i),c.push(f))}}}),n.fn.extend({domManip:Ha,detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return Y(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||d).createTextNode(a))},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(ea(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,\"select\")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return Y(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(ta,\"\"):void 0;if(\"string\"==typeof a&&!wa.test(a)&&(l.htmlSerialize||!ua.test(a))&&(l.leadingWhitespace||!aa.test(a))&&!da[($.exec(a)||[\"\",\"\"])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ea(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(ea(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],f=n(a),h=f.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(f[d])[b](c),g.apply(e,c.get());return this.pushStack(e)}});var Ja,Ka={HTML:\"block\",BODY:\"block\"};function La(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],\"display\");return c.detach(),d}function Ma(a){var b=d,c=Ka[a];return c||(c=La(a,b),\"none\"!==c&&c||(Ja=(Ja||n(\"<iframe frameborder='0' width='0' height='0'/>\")).appendTo(b.documentElement),b=(Ja[0].contentWindow||Ja[0].contentDocument).document,b.write(),b.close(),c=La(a,b),Ja.detach()),Ka[a]=c),c}var Na=/^margin/,Oa=new RegExp(\"^(\"+T+\")(?!px)[a-z%]+$\",\"i\"),Pa=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},Qa=d.documentElement;!function(){var b,c,e,f,g,h,i=d.createElement(\"div\"),j=d.createElement(\"div\");if(j.style){j.style.cssText=\"float:left;opacity:.5\",l.opacity=\"0.5\"===j.style.opacity,l.cssFloat=!!j.style.cssFloat,j.style.backgroundClip=\"content-box\",j.cloneNode(!0).style.backgroundClip=\"\",l.clearCloneStyle=\"content-box\"===j.style.backgroundClip,i=d.createElement(\"div\"),i.style.cssText=\"border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute\",j.innerHTML=\"\",i.appendChild(j),l.boxSizing=\"\"===j.style.boxSizing||\"\"===j.style.MozBoxSizing||\"\"===j.style.WebkitBoxSizing,n.extend(l,{reliableHiddenOffsets:function(){return null==b&&k(),f},boxSizingReliable:function(){return null==b&&k(),e},pixelMarginRight:function(){return null==b&&k(),c},pixelPosition:function(){return null==b&&k(),b},reliableMarginRight:function(){return null==b&&k(),g},reliableMarginLeft:function(){return null==b&&k(),h}});function k(){var k,l,m=d.documentElement;m.appendChild(i),j.style.cssText=\"-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%\",b=e=h=!1,c=g=!0,a.getComputedStyle&&(l=a.getComputedStyle(j),b=\"1%\"!==(l||{}).top,h=\"2px\"===(l||{}).marginLeft,e=\"4px\"===(l||{width:\"4px\"}).width,j.style.marginRight=\"50%\",c=\"4px\"===(l||{marginRight:\"4px\"}).marginRight,k=j.appendChild(d.createElement(\"div\")),k.style.cssText=j.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0\",k.style.marginRight=k.style.width=\"0\",j.style.width=\"1px\",g=!parseFloat((a.getComputedStyle(k)||{}).marginRight),j.removeChild(k)),j.style.display=\"none\",f=0===j.getClientRects().length,f&&(j.style.display=\"\",j.innerHTML=\"<table><tr><td></td><td>t</td></tr></table>\",j.childNodes[0].style.borderCollapse=\"separate\",k=j.getElementsByTagName(\"td\"),k[0].style.cssText=\"margin:0;border:0;padding:0;display:none\",f=0===k[0].offsetHeight,f&&(k[0].style.display=\"\",k[1].style.display=\"none\",f=0===k[0].offsetHeight)),m.removeChild(i)}}}();var Ra,Sa,Ta=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ra=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)},Sa=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ra(a),g=c?c.getPropertyValue(b)||c[b]:void 0,\"\"!==g&&void 0!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),c&&!l.pixelMarginRight()&&Oa.test(g)&&Na.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f),void 0===g?g:g+\"\"}):Qa.currentStyle&&(Ra=function(a){return a.currentStyle},Sa=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ra(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Oa.test(g)&&!Ta.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left=\"fontSize\"===b?\"1em\":g,g=h.pixelLeft+\"px\",h.left=d,f&&(e.left=f)),void 0===g?g:g+\"\"||\"auto\"});function Ua(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Va=/alpha\\([^)]*\\)/i,Wa=/opacity\\s*=\\s*([^)]*)/i,Xa=/^(none|table(?!-c[ea]).+)/,Ya=new RegExp(\"^(\"+T+\")(.*)$\",\"i\"),Za={position:\"absolute\",visibility:\"hidden\",display:\"block\"},$a={letterSpacing:\"0\",fontWeight:\"400\"},_a=[\"Webkit\",\"O\",\"Moz\",\"ms\"],ab=d.createElement(\"div\").style;function bb(a){if(a in ab)return a;var b=a.charAt(0).toUpperCase()+a.slice(1),c=_a.length;while(c--)if(a=_a[c]+b,a in ab)return a}function cb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,\"olddisplay\"),c=d.style.display,b?(f[g]||\"none\"!==c||(d.style.display=\"\"),\"\"===d.style.display&&W(d)&&(f[g]=n._data(d,\"olddisplay\",Ma(d.nodeName)))):(e=W(d),(c&&\"none\"!==c||!e)&&n._data(d,\"olddisplay\",e?c:n.css(d,\"display\"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&\"none\"!==d.style.display&&\"\"!==d.style.display||(d.style.display=b?f[g]||\"\":\"none\"));return a}function db(a,b,c){var d=Ya.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||\"px\"):b}function eb(a,b,c,d,e){for(var f=c===(d?\"border\":\"content\")?4:\"width\"===b?1:0,g=0;4>f;f+=2)\"margin\"===c&&(g+=n.css(a,c+V[f],!0,e)),d?(\"content\"===c&&(g-=n.css(a,\"padding\"+V[f],!0,e)),\"margin\"!==c&&(g-=n.css(a,\"border\"+V[f]+\"Width\",!0,e))):(g+=n.css(a,\"padding\"+V[f],!0,e),\"padding\"!==c&&(g+=n.css(a,\"border\"+V[f]+\"Width\",!0,e)));return g}function fb(a,b,c){var d=!0,e=\"width\"===b?a.offsetWidth:a.offsetHeight,f=Ra(a),g=l.boxSizing&&\"border-box\"===n.css(a,\"boxSizing\",!1,f);if(0>=e||null==e){if(e=Sa(a,b,f),(0>e||null==e)&&(e=a.style[b]),Oa.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+eb(a,b,c||(g?\"border\":\"content\"),d,f)+\"px\"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Sa(a,\"opacity\");return\"\"===c?\"1\":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":l.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=bb(h)||h),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&\"get\"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,\"string\"===f&&(e=U.exec(c))&&e[1]&&(c=X(a,b,e),f=\"number\"),null!=c&&c===c&&(\"number\"===f&&(c+=e&&e[3]||(n.cssNumber[h]?\"\":\"px\")),l.clearCloneStyle||\"\"!==c||0!==b.indexOf(\"background\")||(i[b]=\"inherit\"),!(g&&\"set\"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=bb(h)||h),g=n.cssHooks[b]||n.cssHooks[h],g&&\"get\"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Sa(a,b,d)),\"normal\"===f&&b in $a&&(f=$a[b]),\"\"===c||c?(e=parseFloat(f),c===!0||isFinite(e)?e||0:f):f}}),n.each([\"height\",\"width\"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?Xa.test(n.css(a,\"display\"))&&0===a.offsetWidth?Pa(a,Za,function(){return fb(a,b,d)}):fb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ra(a);return db(a,c,d?eb(a,b,d,l.boxSizing&&\"border-box\"===n.css(a,\"boxSizing\",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Wa.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||\"\")?.01*parseFloat(RegExp.$1)+\"\":b?\"1\":\"\"},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?\"alpha(opacity=\"+100*b+\")\":\"\",f=d&&d.filter||c.filter||\"\";c.zoom=1,(b>=1||\"\"===b)&&\"\"===n.trim(f.replace(Va,\"\"))&&c.removeAttribute&&(c.removeAttribute(\"filter\"),\"\"===b||d&&!d.filter)||(c.filter=Va.test(f)?f.replace(Va,e):f+\" \"+e)}}),n.cssHooks.marginRight=Ua(l.reliableMarginRight,function(a,b){return b?Pa(a,{display:\"inline-block\"},Sa,[a,\"marginRight\"]):void 0}),n.cssHooks.marginLeft=Ua(l.reliableMarginLeft,function(a,b){return b?(parseFloat(Sa(a,\"marginLeft\"))||(n.contains(a.ownerDocument,a)?a.getBoundingClientRect().left-Pa(a,{\n marginLeft:0},function(){return a.getBoundingClientRect().left}):0))+\"px\":void 0}),n.each({margin:\"\",padding:\"\",border:\"Width\"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f=\"string\"==typeof c?c.split(\" \"):[c];4>d;d++)e[a+V[d]+b]=f[d]||f[d-2]||f[0];return e}},Na.test(a)||(n.cssHooks[a+b].set=db)}),n.fn.extend({css:function(a,b){return Y(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Ra(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return cb(this,!0)},hide:function(){return cb(this)},toggle:function(a){return\"boolean\"==typeof a?a?this.show():this.hide():this.each(function(){W(this)?n(this).show():n(this).hide()})}});function gb(a,b,c,d,e){return new gb.prototype.init(a,b,c,d,e)}n.Tween=gb,gb.prototype={constructor:gb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||n.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?\"\":\"px\")},cur:function(){var a=gb.propHooks[this.prop];return a&&a.get?a.get(this):gb.propHooks._default.get(this)},run:function(a){var b,c=gb.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):gb.propHooks._default.set(this),this}},gb.prototype.init.prototype=gb.prototype,gb.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=n.css(a.elem,a.prop,\"\"),b&&\"auto\"!==b?b:0)},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[n.cssProps[a.prop]]&&!n.cssHooks[a.prop]?a.elem[a.prop]=a.now:n.style(a.elem,a.prop,a.now+a.unit)}}},gb.propHooks.scrollTop=gb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:\"swing\"},n.fx=gb.prototype.init,n.fx.step={};var hb,ib,jb=/^(?:toggle|show|hide)$/,kb=/queueHooks$/;function lb(){return a.setTimeout(function(){hb=void 0}),hb=n.now()}function mb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=V[e],d[\"margin\"+c]=d[\"padding\"+c]=a;return b&&(d.opacity=d.width=a),d}function nb(a,b,c){for(var d,e=(qb.tweeners[b]||[]).concat(qb.tweeners[\"*\"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ob(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&W(a),r=n._data(a,\"fxshow\");c.queue||(h=n._queueHooks(a,\"fx\"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,\"fx\").length||h.empty.fire()})})),1===a.nodeType&&(\"height\"in b||\"width\"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,\"display\"),k=\"none\"===j?n._data(a,\"olddisplay\")||Ma(a.nodeName):j,\"inline\"===k&&\"none\"===n.css(a,\"float\")&&(l.inlineBlockNeedsLayout&&\"inline\"!==Ma(a.nodeName)?p.zoom=1:p.display=\"inline-block\")),c.overflow&&(p.overflow=\"hidden\",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],jb.exec(e)){if(delete b[d],f=f||\"toggle\"===e,e===(q?\"hide\":\"show\")){if(\"show\"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(o))\"inline\"===(\"none\"===j?Ma(a.nodeName):j)&&(p.display=j);else{r?\"hidden\"in r&&(q=r.hidden):r=n._data(a,\"fxshow\",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,\"fxshow\");for(b in o)n.style(a,b,o[b])});for(d in o)g=nb(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start=\"width\"===d||\"height\"===d?1:0))}}function pb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&\"expand\"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function qb(a,b,c){var d,e,f=0,g=qb.prefilters.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=hb||lb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{},easing:n.easing._default},c),originalProperties:b,originalOptions:c,startTime:hb||lb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(pb(k,j.opts.specialEasing);g>f;f++)if(d=qb.prefilters[f].call(j,a,k,j.opts))return n.isFunction(d.stop)&&(n._queueHooks(j.elem,j.opts.queue).stop=n.proxy(d.stop,d)),d;return n.map(k,nb,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(qb,{tweeners:{\"*\":[function(a,b){var c=this.createTween(a,b);return X(c.elem,a,U.exec(b),c),c}]},tweener:function(a,b){n.isFunction(a)?(b=a,a=[\"*\"]):a=a.match(G);for(var c,d=0,e=a.length;e>d;d++)c=a[d],qb.tweeners[c]=qb.tweeners[c]||[],qb.tweeners[c].unshift(b)},prefilters:[ob],prefilter:function(a,b){b?qb.prefilters.unshift(a):qb.prefilters.push(a)}}),n.speed=function(a,b,c){var d=a&&\"object\"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:\"number\"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,null!=d.queue&&d.queue!==!0||(d.queue=\"fx\"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(W).css(\"opacity\",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=qb(this,n.extend({},a),f);(e||n._data(this,\"finish\"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return\"string\"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||\"fx\",[]),this.each(function(){var b=!0,e=null!=a&&a+\"queueHooks\",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&kb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||\"fx\"),this.each(function(){var b,c=n._data(this),d=c[a+\"queue\"],e=c[a+\"queueHooks\"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each([\"toggle\",\"show\",\"hide\"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||\"boolean\"==typeof a?c.apply(this,arguments):this.animate(mb(b,!0),a,d,e)}}),n.each({slideDown:mb(\"show\"),slideUp:mb(\"hide\"),slideToggle:mb(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(hb=n.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||n.fx.stop(),hb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){ib||(ib=a.setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){a.clearInterval(ib),ib=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(b,c){return b=n.fx?n.fx.speeds[b]||b:b,c=c||\"fx\",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a,b=d.createElement(\"input\"),c=d.createElement(\"div\"),e=d.createElement(\"select\"),f=e.appendChild(d.createElement(\"option\"));c=d.createElement(\"div\"),c.setAttribute(\"className\",\"t\"),c.innerHTML=\" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",a=c.getElementsByTagName(\"a\")[0],b.setAttribute(\"type\",\"checkbox\"),c.appendChild(b),a=c.getElementsByTagName(\"a\")[0],a.style.cssText=\"top:1px\",l.getSetAttribute=\"t\"!==c.className,l.style=/top/.test(a.getAttribute(\"style\")),l.hrefNormalized=\"/a\"===a.getAttribute(\"href\"),l.checkOn=!!b.value,l.optSelected=f.selected,l.enctype=!!d.createElement(\"form\").enctype,e.disabled=!0,l.optDisabled=!f.disabled,b=d.createElement(\"input\"),b.setAttribute(\"value\",\"\"),l.input=\"\"===b.getAttribute(\"value\"),b.value=\"t\",b.setAttribute(\"type\",\"radio\"),l.radioValue=\"t\"===b.value}();var rb=/\\r/g,sb=/[\\x20\\t\\r\\n\\f]+/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e=\"\":\"number\"==typeof e?e+=\"\":n.isArray(e)&&(e=n.map(e,function(a){return null==a?\"\":a+\"\"})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&\"set\"in b&&void 0!==b.set(this,e,\"value\")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&\"get\"in b&&void 0!==(c=b.get(e,\"value\"))?c:(c=e.value,\"string\"==typeof c?c.replace(rb,\"\"):null==c?\"\":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,\"value\");return null!=b?b:n.trim(n.text(a)).replace(sb,\" \")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f=\"select-one\"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],(c.selected||i===e)&&(l.optDisabled?!c.disabled:null===c.getAttribute(\"disabled\"))&&(!c.parentNode.disabled||!n.nodeName(c.parentNode,\"optgroup\"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>-1)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each([\"radio\",\"checkbox\"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>-1:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute(\"value\")?\"on\":a.value})});var tb,ub,vb=n.expr.attrHandle,wb=/^(?:checked|selected)$/i,xb=l.getSetAttribute,yb=l.input;n.fn.extend({attr:function(a,b){return Y(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return\"undefined\"==typeof a.getAttribute?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),e=n.attrHooks[b]||(n.expr.match.bool.test(b)?ub:tb)),void 0!==c?null===c?void n.removeAttr(a,b):e&&\"set\"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+\"\"),c):e&&\"get\"in e&&null!==(d=e.get(a,b))?d:(d=n.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&\"radio\"===b&&n.nodeName(a,\"input\")){var c=a.value;return a.setAttribute(\"type\",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(G);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?yb&&xb||!wb.test(c)?a[d]=!1:a[n.camelCase(\"default-\"+c)]=a[d]=!1:n.attr(a,c,\"\"),a.removeAttribute(xb?c:d)}}),ub={set:function(a,b,c){return b===!1?n.removeAttr(a,c):yb&&xb||!wb.test(c)?a.setAttribute(!xb&&n.propFix[c]||c,c):a[n.camelCase(\"default-\"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\\w+/g),function(a,b){var c=vb[b]||n.find.attr;yb&&xb||!wb.test(b)?vb[b]=function(a,b,d){var e,f;return d||(f=vb[b],vb[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,vb[b]=f),e}:vb[b]=function(a,b,c){return c?void 0:a[n.camelCase(\"default-\"+b)]?b.toLowerCase():null}}),yb&&xb||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,\"input\")?void(a.defaultValue=b):tb&&tb.set(a,b,c)}}),xb||(tb={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+=\"\",\"value\"===c||b===a.getAttribute(c)?b:void 0}},vb.id=vb.name=vb.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&\"\"!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:tb.set},n.attrHooks.contenteditable={set:function(a,b,c){tb.set(a,\"\"===b?!1:b,c)}},n.each([\"width\",\"height\"],function(a,b){n.attrHooks[b]={set:function(a,c){return\"\"===c?(a.setAttribute(b,\"auto\"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+\"\"}});var zb=/^(?:input|select|textarea|button|object)$/i,Ab=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return Y(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&n.isXMLDoc(a)||(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&\"set\"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&\"get\"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,\"tabindex\");return b?parseInt(b,10):zb.test(a.nodeName)||Ab.test(a.nodeName)&&a.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),l.hrefNormalized||n.each([\"href\",\"src\"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),n.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype=\"encoding\");var Bb=/[\\t\\r\\n\\f]/g;function Cb(a){return n.attr(a,\"class\")||\"\"}n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,Cb(this)))});if(\"string\"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=Cb(c),d=1===c.nodeType&&(\" \"+e+\" \").replace(Bb,\" \")){g=0;while(f=b[g++])d.indexOf(\" \"+f+\" \")<0&&(d+=f+\" \");h=n.trim(d),e!==h&&n.attr(c,\"class\",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,Cb(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if(\"string\"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=Cb(c),d=1===c.nodeType&&(\" \"+e+\" \").replace(Bb,\" \")){g=0;while(f=b[g++])while(d.indexOf(\" \"+f+\" \")>-1)d=d.replace(\" \"+f+\" \",\" \");h=n.trim(d),e!==h&&n.attr(c,\"class\",h)}}return this},toggleClass:function(a,b){var c=typeof a;return\"boolean\"==typeof b&&\"string\"===c?b?this.addClass(a):this.removeClass(a):n.isFunction(a)?this.each(function(c){n(this).toggleClass(a.call(this,c,Cb(this),b),b)}):this.each(function(){var b,d,e,f;if(\"string\"===c){d=0,e=n(this),f=a.match(G)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&\"boolean\"!==c||(b=Cb(this),b&&n._data(this,\"__className__\",b),n.attr(this,\"class\",b||a===!1?\"\":n._data(this,\"__className__\")||\"\"))})},hasClass:function(a){var b,c,d=0;b=\" \"+a+\" \";while(c=this[d++])if(1===c.nodeType&&(\" \"+Cb(c)+\" \").replace(Bb,\" \").indexOf(b)>-1)return!0;return!1}}),n.each(\"blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu\".split(\" \"),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Db=a.location,Eb=n.now(),Fb=/\\?/,Gb=/(,)|(\\[|{)|(}|])|\"(?:[^\"\\\\\\r\\n]|\\\\[\"\\\\\\/bfnrt]|\\\\u[\\da-fA-F]{4})*\"\\s*:?|true|false|null|-?(?!0\\d)\\d+(?:\\.\\d+|)(?:[eE][+-]?\\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+\"\");var c,d=null,e=n.trim(b+\"\");return e&&!n.trim(e.replace(Gb,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,\"\")}))?Function(\"return \"+e)():n.error(\"Invalid JSON: \"+b)},n.parseXML=function(b){var c,d;if(!b||\"string\"!=typeof b)return null;try{a.DOMParser?(d=new a.DOMParser,c=d.parseFromString(b,\"text/xml\")):(c=new a.ActiveXObject(\"Microsoft.XMLDOM\"),c.async=\"false\",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName(\"parsererror\").length||n.error(\"Invalid XML: \"+b),c};var Hb=/#.*$/,Ib=/([?&])_=[^&]*/,Jb=/^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/gm,Kb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Lb=/^(?:GET|HEAD)$/,Mb=/^\\/\\//,Nb=/^([\\w.+-]+:)(?:\\/\\/(?:[^\\/?#]*@|)([^\\/?#:]*)(?::(\\d+)|)|)/,Ob={},Pb={},Qb=\"*/\".concat(\"*\"),Rb=Db.href,Sb=Nb.exec(Rb.toLowerCase())||[];function Tb(a){return function(b,c){\"string\"!=typeof b&&(c=b,b=\"*\");var d,e=0,f=b.toLowerCase().match(G)||[];if(n.isFunction(c))while(d=f[e++])\"+\"===d.charAt(0)?(d=d.slice(1)||\"*\",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Ub(a,b,c,d){var e={},f=a===Pb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return\"string\"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e[\"*\"]&&g(\"*\")}function Vb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Wb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while(\"*\"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader(\"Content-Type\"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+\" \"+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Xb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if(\"*\"===f)f=i;else if(\"*\"!==i&&i!==f){if(g=j[i+\" \"+f]||j[\"* \"+f],!g)for(e in j)if(h=e.split(\" \"),h[1]===f&&(g=j[i+\" \"+h[0]]||j[\"* \"+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a[\"throws\"])b=g(b);else try{b=g(b)}catch(l){return{state:\"parsererror\",error:g?l:\"No conversion from \"+i+\" to \"+f}}}return{state:\"success\",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Rb,type:\"GET\",isLocal:Kb.test(Sb[1]),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":Qb,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":n.parseJSON,\"text xml\":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Vb(Vb(a,n.ajaxSettings),b):Vb(n.ajaxSettings,a)},ajaxPrefilter:Tb(Ob),ajaxTransport:Tb(Pb),ajax:function(b,c){\"object\"==typeof b&&(c=b,b=void 0),c=c||{};var d,e,f,g,h,i,j,k,l=n.ajaxSetup({},c),m=l.context||l,o=l.context&&(m.nodeType||m.jquery)?n(m):n.event,p=n.Deferred(),q=n.Callbacks(\"once memory\"),r=l.statusCode||{},s={},t={},u=0,v=\"canceled\",w={readyState:0,getResponseHeader:function(a){var b;if(2===u){if(!k){k={};while(b=Jb.exec(g))k[b[1].toLowerCase()]=b[2]}b=k[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===u?g:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return u||(a=t[c]=t[c]||a,s[a]=b),this},overrideMimeType:function(a){return u||(l.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>u)for(b in a)r[b]=[r[b],a[b]];else w.always(a[w.status]);return this},abort:function(a){var b=a||v;return j&&j.abort(b),y(0,b),this}};if(p.promise(w).complete=q.add,w.success=w.done,w.error=w.fail,l.url=((b||l.url||Rb)+\"\").replace(Hb,\"\").replace(Mb,Sb[1]+\"//\"),l.type=c.method||c.type||l.method||l.type,l.dataTypes=n.trim(l.dataType||\"*\").toLowerCase().match(G)||[\"\"],null==l.crossDomain&&(d=Nb.exec(l.url.toLowerCase()),l.crossDomain=!(!d||d[1]===Sb[1]&&d[2]===Sb[2]&&(d[3]||(\"http:\"===d[1]?\"80\":\"443\"))===(Sb[3]||(\"http:\"===Sb[1]?\"80\":\"443\")))),l.data&&l.processData&&\"string\"!=typeof l.data&&(l.data=n.param(l.data,l.traditional)),Ub(Ob,l,c,w),2===u)return w;i=n.event&&l.global,i&&0===n.active++&&n.event.trigger(\"ajaxStart\"),l.type=l.type.toUpperCase(),l.hasContent=!Lb.test(l.type),f=l.url,l.hasContent||(l.data&&(f=l.url+=(Fb.test(f)?\"&\":\"?\")+l.data,delete l.data),l.cache===!1&&(l.url=Ib.test(f)?f.replace(Ib,\"$1_=\"+Eb++):f+(Fb.test(f)?\"&\":\"?\")+\"_=\"+Eb++)),l.ifModified&&(n.lastModified[f]&&w.setRequestHeader(\"If-Modified-Since\",n.lastModified[f]),n.etag[f]&&w.setRequestHeader(\"If-None-Match\",n.etag[f])),(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&w.setRequestHeader(\"Content-Type\",l.contentType),w.setRequestHeader(\"Accept\",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(\"*\"!==l.dataTypes[0]?\", \"+Qb+\"; q=0.01\":\"\"):l.accepts[\"*\"]);for(e in l.headers)w.setRequestHeader(e,l.headers[e]);if(l.beforeSend&&(l.beforeSend.call(m,w,l)===!1||2===u))return w.abort();v=\"abort\";for(e in{success:1,error:1,complete:1})w[e](l[e]);if(j=Ub(Pb,l,c,w)){if(w.readyState=1,i&&o.trigger(\"ajaxSend\",[w,l]),2===u)return w;l.async&&l.timeout>0&&(h=a.setTimeout(function(){w.abort(\"timeout\")},l.timeout));try{u=1,j.send(s,y)}catch(x){if(!(2>u))throw x;y(-1,x)}}else y(-1,\"No Transport\");function y(b,c,d,e){var k,s,t,v,x,y=c;2!==u&&(u=2,h&&a.clearTimeout(h),j=void 0,g=e||\"\",w.readyState=b>0?4:0,k=b>=200&&300>b||304===b,d&&(v=Wb(l,w,d)),v=Xb(l,v,w,k),k?(l.ifModified&&(x=w.getResponseHeader(\"Last-Modified\"),x&&(n.lastModified[f]=x),x=w.getResponseHeader(\"etag\"),x&&(n.etag[f]=x)),204===b||\"HEAD\"===l.type?y=\"nocontent\":304===b?y=\"notmodified\":(y=v.state,s=v.data,t=v.error,k=!t)):(t=y,!b&&y||(y=\"error\",0>b&&(b=0))),w.status=b,w.statusText=(c||y)+\"\",k?p.resolveWith(m,[s,y,w]):p.rejectWith(m,[w,y,t]),w.statusCode(r),r=void 0,i&&o.trigger(k?\"ajaxSuccess\":\"ajaxError\",[w,l,k?s:t]),q.fireWith(m,[w,y]),i&&(o.trigger(\"ajaxComplete\",[w,l]),--n.active||n.event.trigger(\"ajaxStop\")))}return w},getJSON:function(a,b,c){return n.get(a,b,c,\"json\")},getScript:function(a,b){return n.get(a,void 0,b,\"script\")}}),n.each([\"get\",\"post\"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax(n.extend({url:a,type:b,dataType:e,data:c,success:d},n.isPlainObject(a)&&a))}}),n._evalUrl=function(a){return n.ajax({url:a,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,\"throws\":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return n.isFunction(a)?this.each(function(b){n(this).wrapInner(a.call(this,b))}):this.each(function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,\"body\")||n(this).replaceWith(this.childNodes)}).end()}});function Yb(a){return a.style&&a.style.display||n.css(a,\"display\")}function Zb(a){if(!n.contains(a.ownerDocument||d,a))return!0;while(a&&1===a.nodeType){if(\"none\"===Yb(a)||\"hidden\"===a.type)return!0;a=a.parentNode}return!1}n.expr.filters.hidden=function(a){return l.reliableHiddenOffsets()?a.offsetWidth<=0&&a.offsetHeight<=0&&!a.getClientRects().length:Zb(a)},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var $b=/%20/g,_b=/\\[\\]$/,ac=/\\r?\\n/g,bc=/^(?:submit|button|image|reset|file)$/i,cc=/^(?:input|select|textarea|keygen)/i;function dc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||_b.test(a)?d(a,e):dc(a+\"[\"+(\"object\"==typeof e&&null!=e?b:\"\")+\"]\",e,c,d)});else if(c||\"object\"!==n.type(b))d(a,b);else for(e in b)dc(a+\"[\"+e+\"]\",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?\"\":b,d[d.length]=encodeURIComponent(a)+\"=\"+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)dc(c,a[c],b,e);return d.join(\"&\").replace($b,\"+\")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,\"elements\");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(\":disabled\")&&cc.test(this.nodeName)&&!bc.test(a)&&(this.checked||!Z.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(ac,\"\\r\\n\")}}):{name:b.name,value:c.replace(ac,\"\\r\\n\")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return this.isLocal?ic():d.documentMode>8?hc():/^(get|post|head|put|delete|options)$/i.test(this.type)&&hc()||ic()}:hc;var ec=0,fc={},gc=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent(\"onunload\",function(){for(var a in fc)fc[a](void 0,!0)}),l.cors=!!gc&&\"withCredentials\"in gc,gc=l.ajax=!!gc,gc&&n.ajaxTransport(function(b){if(!b.crossDomain||l.cors){var c;return{send:function(d,e){var f,g=b.xhr(),h=++ec;if(g.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(f in b.xhrFields)g[f]=b.xhrFields[f];b.mimeType&&g.overrideMimeType&&g.overrideMimeType(b.mimeType),b.crossDomain||d[\"X-Requested-With\"]||(d[\"X-Requested-With\"]=\"XMLHttpRequest\");for(f in d)void 0!==d[f]&&g.setRequestHeader(f,d[f]+\"\");g.send(b.hasContent&&b.data||null),c=function(a,d){var f,i,j;if(c&&(d||4===g.readyState))if(delete fc[h],c=void 0,g.onreadystatechange=n.noop,d)4!==g.readyState&&g.abort();else{j={},f=g.status,\"string\"==typeof g.responseText&&(j.text=g.responseText);try{i=g.statusText}catch(k){i=\"\"}f||!b.isLocal||b.crossDomain?1223===f&&(f=204):f=j.text?200:404}j&&e(f,i,j,g.getAllResponseHeaders())},b.async?4===g.readyState?a.setTimeout(c):g.onreadystatechange=fc[h]=c:c()},abort:function(){c&&c(void 0,!0)}}}});function hc(){try{return new a.XMLHttpRequest}catch(b){}}function ic(){try{return new a.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(b){}}n.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter(\"script\",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type=\"GET\",a.global=!1)}),n.ajaxTransport(\"script\",function(a){if(a.crossDomain){var b,c=d.head||n(\"head\")[0]||d.documentElement;return{send:function(e,f){b=d.createElement(\"script\"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||f(200,\"success\"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var jc=[],kc=/(=)\\?(?=&|$)|\\?\\?/;n.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var a=jc.pop()||n.expando+\"_\"+Eb++;return this[a]=!0,a}}),n.ajaxPrefilter(\"json jsonp\",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(kc.test(b.url)?\"url\":\"string\"==typeof b.data&&0===(b.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&kc.test(b.data)&&\"data\");return h||\"jsonp\"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(kc,\"$1\"+e):b.jsonp!==!1&&(b.url+=(Fb.test(b.url)?\"&\":\"?\")+b.jsonp+\"=\"+e),b.converters[\"script json\"]=function(){return g||n.error(e+\" was not called\"),g[0]},b.dataTypes[0]=\"json\",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?n(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,jc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),\"script\"):void 0}),n.parseHTML=function(a,b,c){if(!a||\"string\"!=typeof a)return null;\"boolean\"==typeof b&&(c=b,b=!1),b=b||d;var e=x.exec(a),f=!c&&[];return e?[b.createElement(e[1])]:(e=ja([a],b,f),f&&f.length&&n(f).remove(),n.merge([],e.childNodes))};var lc=n.fn.load;n.fn.load=function(a,b,c){if(\"string\"!=typeof a&&lc)return lc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(\" \");return h>-1&&(d=n.trim(a.slice(h,a.length)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&\"object\"==typeof b&&(e=\"POST\"),g.length>0&&n.ajax({url:a,type:e||\"GET\",dataType:\"html\",data:b}).done(function(a){f=arguments,g.html(d?n(\"<div>\").append(n.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},n.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};function mc(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,\"position\"),l=n(a),m={};\"static\"===k&&(a.style.position=\"relative\"),h=l.offset(),f=n.css(a,\"top\"),i=n.css(a,\"left\"),j=(\"absolute\"===k||\"fixed\"===k)&&n.inArray(\"auto\",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,n.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),\"using\"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(\"undefined\"!=typeof e.getBoundingClientRect&&(d=e.getBoundingClientRect()),c=mc(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return\"fixed\"===n.css(d,\"position\")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],\"html\")||(c=a.offset()),c.top+=n.css(a[0],\"borderTopWidth\",!0),c.left+=n.css(a[0],\"borderLeftWidth\",!0)),{top:b.top-c.top-n.css(d,\"marginTop\",!0),left:b.left-c.left-n.css(d,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&!n.nodeName(a,\"html\")&&\"static\"===n.css(a,\"position\"))a=a.offsetParent;return a||Qa})}}),n.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return Y(this,function(a,d,e){var f=mc(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each([\"top\",\"left\"],function(a,b){n.cssHooks[b]=Ua(l.pixelPosition,function(a,c){return c?(c=Sa(a,b),Oa.test(c)?n(a).position()[b]+\"px\":c):void 0})}),n.each({Height:\"height\",Width:\"width\"},function(a,b){n.each({\n padding:\"inner\"+a,content:b,\"\":\"outer\"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||\"boolean\"!=typeof d),g=c||(d===!0||e===!0?\"margin\":\"border\");return Y(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement[\"client\"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body[\"scroll\"+a],e[\"scroll\"+a],b.body[\"offset\"+a],e[\"offset\"+a],e[\"client\"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,\"**\"):this.off(b,a||\"**\",c)}}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return n});var nc=a.jQuery,oc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=oc),b&&a.jQuery===n&&(a.jQuery=nc),n},b||(a.jQuery=a.$=n),n});\n",
39
39
  "'use strict';\nif ( typeof(module) !== 'undefined' && module.exports ) {\n var lib = require('../../index');\n}\n\n/**\n * Collection cLass\n * Allows you to handle your own collections as you would normaly with mongodb\n * Dependencies :\n * - lib/merge\n * - uuid\n *\n *\n * @param {array} collection\n * @param {object} [options]\n *\n * @return {object} instance\n * \n * Collection.length will return result length : dont't use .count() which is going to include functions to the count\n *\n * Collection::find\n * @param {object} filter\n * eg.: { uid: 'someUID' }\n * eg.: { type: 'not null', country: 'France' } // `AND` clause\n * NB.: To filter `not empty`, use { type: '!=\"\"' }\n * eg.: { country: 'The Hashemite Kingdom of Jordan' }, { country: 'Libanon'} // `OR` clause \n * eg.: { 'obj.prop': true }\n * eg.: { 'contacts[*].name': 'Doe' } // `WITHIN` (array|collection) clause\n * eg.: { lastUpdate: '>= 2016-12-01T00:00:00' } // also available for date comparison `=`, `<`, `>`\n * eg.: { activity: null }\n * eg.: { isActive: false }\n *\n * @return {array} result\n *\n * Collection::findOne\n * @param {object} filter\n * @return {object|array|string} result\n *\n * Collection::update\n * @param {object} filter\n * @param {object} set\n *\n * @return {array} result\n * rasult.toRaw() will give result without chaining & _uuid\n *\n * */\nfunction Collection(content, options) {\n\n var isGFFCtx = ( ( typeof(module) !== 'undefined' ) && module.exports ) ? false : true;\n var uuid = (isGFFCtx) ? require('vendor/uuid') : require('uuid');\n var merge = (isGFFCtx) ? require('utils/merge') : require('../../../lib/merge');\n\n // defined search option rules\n var searchOptionRules = {\n isCaseSensitive: {\n false: {\n re: '^%s$',\n modifiers: 'i'\n },\n true: {\n re: '^%s$'\n }\n }\n };\n var withOrClause = false;\n var notInSearchModeEnabled = false;\n \n var localSearchOptions = null;\n \n var defaultOptions = {\n useLocalStorage: false,\n locale: 'en', // TODO - get settigs.region, or user.region\n searchOptionRules: searchOptionRules\n };\n \n \n \n options = (typeof(options) == 'object') ? merge(options, defaultOptions) : defaultOptions;\n\n var keywords = ['not null']; // TODO - null, exists (`true` if property is defined)\n var tryEval = function(condition) {\n try {\n return eval(condition);\n } catch(err) {\n throw new Error('Could not evaluate condition `'+ condition +'`.\\n' + err.stack );\n }\n }\n\n if (typeof(content) == 'undefined' || content == '' || content == null)\n content = [];\n\n if ( !Array.isArray(content) )\n throw new Error('`new Collection([content] [, options] )`: `content` argument must be an Array !');\n\n content = (content) ? JSON.clone(content) : []; // original content -> not to be touched\n \n // Indexing : uuids are generated for each entry\n var searchIndex = [], idx = 0;\n for (var entry = 0, entryLen = content.length; entry < entryLen; ++entry) {\n if (!content[entry]) {\n content[entry] = {};\n }\n content[entry]._uuid = uuid.v4();\n // To avoid duplicate entries\n searchIndex[idx] = content[entry]._uuid;\n ++idx;\n }\n\n var instance = content; \n /**\n * Set local search option for the current collection method call\n * \n * eg.: \n * var recCollection = new Collection(arrayCollection);\n * var rec = recCollection\n * .setSearchOption('name', 'isCaseSensitive', false)\n * .find({ city: 'cap Town' });\n * \n * eg.:\n * var recCollection = new Collection(arrayCollection);\n * var searchOptions = {\n * name: {\n * isCaseSensitive: false\n * }\n * };\n * var rec = recCollection\n * .setSearchOption(searchOptions)\n * .find({ city: 'cap Town' }); * \n * \n * @param {object|string} searchOptionObject or searchOptionTargetedProperty\n * @param {string} [searchRule]\n * @param {boolean} [searchRuleValue] - true to enable, false to disabled\n * \n * @return {object} instance with local search options\n */\n instance['setSearchOption'] = function() {\n \n if (!arguments.length)\n throw new Error('searchOption cannot be left blank');\n \n if (arguments.length > 3 || arguments.length < 3 && arguments.length > 1)\n throw new Error('argument length mismatch');\n \n var i = 0\n , len = arguments.length\n ;\n \n if (arguments.length == 1) {\n if ( typeof(arguments[0]) != 'object' )\n throw new Error('searchOption must be an object');\n \n for (var prop in arguments[0]) {\n if ( typeof(searchOptionRules[prop]) == 'undefined' )\n throw new Error(arguments[1] + ' is not an allowed searchOption !');\n }\n \n localSearchOptions = arguments[0];\n } else {\n \n if ( !localSearchOptions )\n localSearchOptions = {};\n \n for (; i < len; ++i) { \n if ( typeof(searchOptionRules[arguments[1]]) == 'undefined' )\n throw new Error(arguments[1] + ' is not an allowed searchOption !');\n \n if (typeof(localSearchOptions[arguments[0]]) == 'undefined')\n localSearchOptions[arguments[0]] = {};\n \n if ( /true|false/i.test(arguments[2]) ) {\n localSearchOptions[arguments[0]][arguments[1]] = /true/i.test(arguments[2]) ? true : false\n } else {\n localSearchOptions[arguments[0]][arguments[1]] = arguments[2]\n } \n }\n } \n \n return instance\n }\n\n \n instance['find'] = function() {\n // reset \n withOrClause = false;\n \n if ( typeof(arguments[arguments.length-1]) == 'boolean' ) {\n withOrClause = arguments[arguments.length-1];\n delete arguments[arguments.length-1];\n --arguments.length;\n }\n\n var filtersStr = null;\n var filters = null;\n var filtersCount = null;\n try {\n filtersStr = JSON.stringify(arguments);\n filters = JSON.parse(filtersStr);\n filtersCount = filters.count();\n } catch( filtersError) {\n throw new Error('filter must be an object\\n'+ filtersError.stack); \n } \n \n if ( typeof(filters) != 'undefined' && filtersCount > 0 ) {\n \n if (filtersCount > 1) {\n withOrClause = true; \n }\n // checking filter : this should be forbidden -> { type: 'red', type: 'orange'}\n // var filtersFields = null;\n // for (let f = 0, fLen = filters.count(); f < fLen; f++) {\n // filtersFields = {};\n // for (let fField in filters[f]) {\n // if ( typeof(filtersFields[ fField ]) != 'undefined' ) {\n // throw new Error('Filter field can only be defined once inside a filter object !\\n`Field '+ fField +'` is already defined : '+ filters[f])\n // }\n // filtersFields[ fField ] = true;\n // }\n // }\n \n var filter = null\n , condition = null\n , i = 0\n //, tmpContent = ( Array.isArray(this) && !withOrClause) ? this : JSON.clone(content)\n , tmpContent = ( Array.isArray(this) ) ? this : JSON.clone(content)\n , resultObj = {}\n , result = []\n , localeLowerCase = ''\n , re = null\n , field = null\n , fieldWithin = null\n , value = null\n , searchOptions = localSearchOptions\n , searchOptionRules = options.searchOptionRules\n ;\n\n var matched = null\n , filterIsArray = null\n , searchResult = [];\n \n /**\n * Regular Search\n * @param {object} filter \n * @param {string} field \n * @param {strine|number|date} _content \n * @param {number} matched \n */\n var search = function(filter, field, _content, matched, searchOptionRules) {\n var reValidCount = null, searchOptCount = null;\n if (filter === null && _content === null) { // null case\n\n ++matched;\n\n } else if (\n filter \n && keywords.indexOf(localeLowerCase) > -1 \n && localeLowerCase == 'not null' \n && typeof(_content) != 'undefined' \n && typeof(_content) !== 'object' \n && _content != 'null' \n && _content != 'undefined'\n ) {\n \n if (result.indexOf(_content) < 0) {\n ++matched;\n }\n\n } else if ( \n typeof(_content) != 'undefined' \n && typeof(_content) !== 'object' \n && /(<|>|=)/.test(filter) \n && !/undefined|function/.test(typeof(_content))\n ) { // with operations\n let originalFilter = filter;\n let condition = _content + filter;\n if ( typeof(filter) == 'string' && typeof(_content) == 'string' ) {\n let comparedValue = filter.replace(/^(<=|>=|!==|!=|===|!==)/g, '');\n if ( typeof(_content) == 'string' && !/^\\\"(.*)\\\"$/.test(comparedValue) ) {\n filter = filter.replace(comparedValue, '\\\"'+ comparedValue + '\\\"');\n }\n condition = '\\\"'+_content+'\\\"' + filter;\n // restoring in case of datetime eval\n filter = originalFilter;\n }\n \n // looking for a datetime ?\n if (\n /(\\d{4})\\-(\\d{2})\\-(\\d{2})(\\s+|T)(\\d{2}):(\\d{2}):(\\d{2})/.test(_content)\n && /(\\d{4})\\-(\\d{2})\\-(\\d{2})(\\s+|T)(\\d{2}):(\\d{2}):(\\d{2})/.test(filter)\n ) {\n\n if (tryEval(_content.replace(/(\\d{4})\\-(\\d{2})\\-(\\d{2})(\\s+|T)(\\d{2}):(\\d{2}):(\\d{2})/, 'new Date(\"$&\")') + filter.replace(/(\\d{4})\\-(\\d{2})\\-(\\d{2})(\\s+|T)(\\d{2}):(\\d{2}):(\\d{2})/, 'new Date(\"$&\")'))) {\n ++matched;\n }\n\n } else if (tryEval(condition)) {\n ++matched;\n }\n\n } else if ( \n typeof(_content) != 'undefined' \n && typeof(_content) !== 'object' \n && _content === filter\n && !searchOptions\n ||\n typeof(_content) != 'undefined' \n && typeof(_content) !== 'object' \n && _content === filter\n && typeof(searchOptions[field]) == 'undefined'\n ) {\n\n ++matched;\n } else if ( \n typeof(_content) != 'undefined' \n && typeof(_content) !== 'object' \n && searchOptions\n && typeof(searchOptions[field]) != 'undefined'\n ) {\n \n reValidCount = 0;\n searchOptCount = searchOptions[field].count();\n for ( var rule in searchOptions[field]) {\n searchOptionRules[rule][searchOptions[field][rule]].re = searchOptionRules[rule][searchOptions[field][rule]].re.replace(/\\%s/, filter);\n \n if (searchOptionRules[rule][searchOptions[field][rule]].modifiers) {\n re = new RegExp(searchOptionRules[rule][searchOptions[field][rule]].re, searchOptionRules[rule][searchOptions[field][rule]].modifiers); \n } else {\n re = new RegExp(searchOptionRules[rule][searchOptions[field][rule]].re);\n }\n \n if ( re.test(_content) ) {\n ++reValidCount\n }\n }\n \n if (reValidCount == searchOptCount) {\n ++matched; \n }\n }\n\n return {\n matched: matched\n };\n }\n\n var searchThroughProp = function(filter, f, _content, matched) {\n\n var field = f.split(/\\./g);\n field = field[field.length - 1];\n re = new RegExp('(\"' + field + '\":\\\\w+)');\n \n var value = null;\n \n try {\n if ( _content )\n value = eval('_content.'+f);\n } catch (err) {\n // Nothing to do\n // means that the field is not available in the collection\n } \n \n \n\n if (value /** && value.length > 0*/) {\n if ( Array.isArray(value) )\n value = value[1].split(/:/)[1];\n else if ( typeof(value) == 'string' && /\\:/.test(value) )\n value = value.split(/:/)[1];\n \n \n if (/(<|>|=)/.test(filter)) {\n\n // looking for a datetime ?\n if (\n /(\\d{4})\\-(\\d{2})\\-(\\d{2})(\\s+|T)(\\d{2}):(\\d{2}):(\\d{2})/.test(value)\n && /(\\d{4})\\-(\\d{2})\\-(\\d{2})(\\s+|T)(\\d{2}):(\\d{2}):(\\d{2})/.test(filter)\n ) {\n\n if (tryEval(value.replace(/(\\d{4})\\-(\\d{2})\\-(\\d{2})(\\s+|T)(\\d{2}):(\\d{2}):(\\d{2})/, 'new Date(\"$&\")') + filter.replace(/(\\d{4})\\-(\\d{2})\\-(\\d{2})(\\s+|T)(\\d{2}):(\\d{2}):(\\d{2})/, 'new Date(\"$&\")'))) {\n\n ++matched;\n }\n\n } else if (tryEval(value + filter)) {\n\n ++matched;\n }\n\n } else {\n if (value == filter) {\n ++matched;\n }\n }\n\n } \n\n return {\n matched: matched\n }\n }\n\n // if one of the entry matches the given filter, tag the whole entry as matched\n var searchWithin = function(filter, f, _content, matched, i) {\n \n var collectionName = null\n , collection = null\n , arr = null\n , field = null;\n\n \n arr = f.split(/\\[\\*\\]/g);\n collectionName = arr[0].replace(/\\[\\*\\]/, '');// only take the first collection\n collection = _content[ collectionName ];\n \n \n field = arr[1];\n if (/^\\./.test(field) )\n field = field.substr(1);\n\n var subMatched = 0;\n if (collection) {\n \n for (var c = 0, cLen = collection.length; c < cLen; ++c) {\n // cases with _filter.prop\n if (/\\./.test(field)) {\n\n searchResult = searchThroughProp(filter, field, collection[c], subMatched);\n subMatched = searchResult.matched;\n\n } else { // normal case\n\n searchResult = search(filter, field, collection[c], subMatched, searchOptionRules);\n subMatched = searchResult.matched;\n }\n\n if (subMatched > 0) break;\n }\n }\n \n return {\n matched: (matched + subMatched)\n }\n }\n\n \n for (var o in tmpContent) {\n\n if (!tmpContent[o]) {\n tmpContent[o] = {}\n }\n \n if (!/undefined|function/.test( typeof(tmpContent[o]))) {\n \n for (let l = 0, lLen = filters.count(); l<lLen; ++l) {\n filter = filters[l];\n condition = filter.count();\n // for each condition \n matched = 0;\n \n for (var f in filter) {\n if ( typeof(filter[f]) == 'undefined' ) throw new Error('filter `'+f+'` cannot be left undefined');\n\n localeLowerCase = ( filter[f] !== null && !/(boolean|number)/.test(typeof(filter[f])) ) ? filter[f].toLocaleLowerCase() : filter[f];\n \n // cases with tmpContent.prop\n if (/\\./.test(f)) {\n //JSON.stringify(tmpContent[o]).match(/(\"gross\":\\w+)/)[1].split(/:/)[1]\n\n // detect if array|collection case\n if (/\\[\\*\\]/.test(f)) {\n\n searchResult = searchWithin(filter[f], f, tmpContent[o], matched, 0);\n matched = searchResult.matched;\n\n } else {\n\n searchResult = searchThroughProp(filter[f], f, tmpContent[o], matched);\n matched = searchResult.matched;\n }\n\n } else { // normal case\n \n searchResult = search(filter[f], f, tmpContent[o][f], matched, searchOptionRules); \n matched = searchResult.matched;\n } \n }\n\n if (matched == condition ) { // all conditions must be fulfilled to match\n // `this` {Array} is the result of the previous search or the current content\n // TODO - Add a switch \n if (\n withOrClause \n && notInSearchModeEnabled\n && searchIndex.indexOf(tmpContent[o]._uuid) < 0 \n || notInSearchModeEnabled\n || !withOrClause\n ) {\n //console.debug('searchIndex ', searchIndex);\n if (!withOrClause || withOrClause && result.indexOf(tmpContent[o]._uuid) < 0 || notInSearchModeEnabled) {\n result[i] = tmpContent[o];\n ++i;\n }\n } else if (\n withOrClause\n && !notInSearchModeEnabled\n ) {\n if (result.indexOf(tmpContent[o]._uuid) < 0) {\n result[i] = tmpContent[o];\n ++i;\n } \n }\n }\n\n }\n \n }\n }\n } else {\n result = content\n }\n\n // reset localSearchOptions for nest calls\n localSearchOptions = null;\n \n // TODO - remove this\n //if (withOrClause) {\n // merging with previous result\n //console.debug('withOrClause: supposed to merge ? \\nnotInSearchModeEnabled: '+notInSearchModeEnabled+'\\nResult: ' +result)//+'\\nThis: '+ this.toRaw();\n // if (!notInSearchModeEnabled) {\n // result = merge(this, result);\n // }\n // TODO - remove this part\n // Removed this on 2021-01-21 because it was causing duplicate content\n //result = merge(this, result, true) \n //}\n\n // chaining\n //result._options = instance._options;\n //result.setSearchOption = instance.setSearchOption;\n \n result.insert = instance.insert;\n result.notIn = instance.notIn;\n result.find = this.find;\n result.update = instance.update;\n result.replace = instance.replace;\n result.or = instance.or;\n result.findOne = instance.findOne;\n result.limit = instance.limit;\n result.orderBy = instance.orderBy;\n result.delete = instance.delete;\n result.toRaw = instance.toRaw;\n result.filter = instance.filter;\n\n return result\n }\n \n /** \n * findOne\n * \n * E.g.: \n * - new Collection(projects).findOne({name: 'My Project'})\n * - new Collection(projects)\n * .setSearchOption({name: { isCaseSensitive: false }})\n * .findOne({name: 'my project'})\n * \n * \n * Available options :\n * isCaseSensitive: [true|false] - set to true by default\n * \n * @param {object} filter\n * \n * @return {object} result\n * \n */\n instance['findOne'] = function() {\n var key = null // comparison key\n , result = null\n , filters = null\n //, uuidSearchModeEnabled = true\n ;\n\n if ( typeof(arguments[arguments.length-1]) == 'string' ) {\n key = arguments[arguments.length - 1];\n delete arguments[arguments.length - 1];\n --arguments.length;\n }\n \n // if ( typeof(arguments[arguments.length-1]) == 'boolean' ) {\n // uuidSearchModeEnabled = arguments[arguments.length - 1]\n // delete arguments[arguments.length - 1];\n // --arguments.length;\n // }\n \n if (arguments.length > 0) {\n filters = arguments;\n }\n \n\n if ( typeof(filters) == 'undefined' || !filters || typeof(filters) != 'object' ) {\n throw new Error('[ Collection ][ findOne ] `filters` argument must be defined: Array or Filter Object(s) expected');\n }\n\n // If an operation (find, insert ...) has been executed, get the previous result; if not, get the whole collection\n //var currentResult = JSON.clone( (Array.isArray(this)) ? this : content );\n var currentResult = null;\n var foundResults = null;\n if ( Array.isArray(arguments[0]) ) {\n foundResults = arguments[0];\n } else {\n foundResults = instance.find.apply(this, arguments) || [];\n }\n \n if (foundResults.length > 0) {\n currentResult = foundResults.limit(1).toRaw()[0]; \n }\n\n result = currentResult;\n return result\n }\n\n\n instance['or'] = function () {\n arguments[arguments.length] = true;\n ++arguments.length;\n\n return instance.find.apply(this, arguments);\n }\n\n instance['limit'] = function(resultLimit) {\n if ( typeof(resultLimit) == 'undefined' || typeof(resultLimit) != 'number' ) {\n throw new Error('[Collection::result->limit(resultLimit)] : `resultLimit` parametter must by a `number`')\n }\n\n var result = Array.isArray(this) ? this : JSON.clone(content);\n\n //resultLimit\n result = result.splice(0, resultLimit);\n\n // chaining\n result.insert = instance.insert;\n result.update = instance.update;\n result.replace = instance.replace;\n result.notIn = instance.notIn;\n result.findOne = instance.findOne;\n result.orderBy = instance.orderBy;\n result.max = instance.max;\n result.delete = instance.delete;\n result.toRaw = instance.toRaw;\n result.filter = instance.filter;\n\n return result\n }\n \n /** \n * notIn\n * Works like a filter to match results by `excluding` through given `filters` !!\n * \n * filter can be like \n * { car: 'toyota' }\n * { car: 'toyota', color: 'red' }\n * \n * You can pass more than one filter\n * { car: 'toyota', color: 'red' }, { car: 'porche' }\n * \n * .notIn(filter) // AND syntax\n * .notIn(filter1, filter2, filter3) // OR syntax\n * .notIn(filter, 'id') where `id` is the uuid used for the DIFF - `_uuid\n * .noIn(collectionObj, 'id')\n * \n * By default, Collection use its own internal `_uuid` to search and compare.\n * This mode is called `uuidSearchModeEnabled`, and it is by default set to `true`.\n * If you want to disable this mode in order to MATCH/DIFF by forcing check on every single filter\n * of the resultset :\n * .notIn(filter, false) where false must be a real boolean\n * \n * \n * \n * @param {object|array} filters|arrayToFilter - works like find filterss\n * @param {string} [key] - unique id for comparison; faster when provided\n */\n instance['notIn'] = function(){\n\n var arrayToFilter = null // [] those that we don't want in the result\n , key = null // string comparison key\n , result = null\n , filters = null\n , uuidSearchModeEnabled = true\n ;\n\n if ( typeof(arguments[arguments.length-1]) == 'string' ) {\n key = arguments[arguments.length - 1];\n delete arguments[arguments.length - 1];\n --arguments.length;\n }\n \n if ( typeof(arguments[arguments.length-1]) == 'boolean' ) {\n uuidSearchModeEnabled = arguments[arguments.length - 1]\n delete arguments[arguments.length - 1];\n --arguments.length;\n }\n \n if (arguments.length > 0) {\n filters = arguments;\n }\n \n\n if ( typeof(filters) == 'undefined' || !filters || typeof(filters) != 'object' ) {\n throw new Error('[ Collection ][ notIn ] `filters` argument must be defined: Array or Filter Object(s) expected');\n }\n\n // If an operation (find, insert ...) has been executed, get the previous result; if not, get the whole collection\n var currentResult = JSON.clone( (Array.isArray(this)) ? this : content );\n \n var foundResults = null;\n if ( Array.isArray(arguments[0]) ) {\n foundResults = arguments[0];\n } else {\n notInSearchModeEnabled = true;\n foundResults = instance.find.apply(this, arguments) || [];\n notInSearchModeEnabled = false;\n }\n \n \n if (foundResults.length > 0) {\n \n // check key\n if ( \n uuidSearchModeEnabled\n && key \n && typeof(foundResults[0]) == 'undefined' \n && typeof(foundResults[0][key]) == 'undefined' \n ) {\n throw new Error('[ Collection ][ notIn ] `key` not valid');\n } else if ( uuidSearchModeEnabled && !key && typeof(foundResults[0]['_uuid']) != 'undefined' ) {\n key = '_uuid'\n } else if ( typeof(foundResults[0]['id']) != 'undefined' ) {\n key = 'id';\n }\n \n if ( !key || typeof(foundResults[0][key]) == 'undefined' ) {\n throw new Error('No comparison key defined !')\n } \n\n // fast search with key\n var r = 0\n , rLen = foundResults.length\n , c = 0\n , cLen = currentResult.length\n , f = 0\n , fLen = filters.count()\n , keyLen = null\n , matched = 0\n , fullFiltersMatched = 0\n ;\n if ( uuidSearchModeEnabled && typeof(currentResult[c]) != 'undefined' && currentResult[c].hasOwnProperty(key) ) {\n // for every single result found \n for (; r < rLen; ++r) {\n \n if (!currentResult.length) break;\n \n c = 0; cLen = currentResult.length;\n for (; c < cLen; ++c) {\n if ( typeof(currentResult[c]) == 'undefined' || typeof(foundResults[r]) == 'undefined' ) {\n continue\n }\n // when matched, we want to remove those not in current result \n if (currentResult[c][key] === foundResults[r][key]) {\n currentResult.splice(c,1);\n break;\n }\n }\n }\n } else if ( typeof(currentResult[c]) == 'undefined' ) { //empty source case\n // means that since we don't have a source to compare, current === found\n currentResult = JSON.clone(foundResults);\n \n } else { // search based on provided filters\n // for every single result found \n for (; r < rLen; ++r) {\n if (!currentResult.length) break; \n \n //onRemoved:\n c = 0; cLen = currentResult.length;\n for (; c < cLen; ++c) { // current results \n \n if ( typeof (currentResult[c]) != 'undefined' ) {\n \n // for each filter\n fullFiltersMatched = 0; \n f = 0; \n for (; f < fLen; ++f ) {\n if ( typeof(filters[f]) == 'undefined' ) throw new Error('filter `'+f+'` cannot be left undefined');\n \n keyLen = filters[f].count();\n matched = 0;\n for (key in filters[f]) {\n if ( currentResult[c].hasOwnProperty(key) && currentResult[c][key] === foundResults[r][key] ) {\n ++matched;\n } \n } \n if (matched == keyLen) {\n ++fullFiltersMatched\n } \n }\n \n if (fullFiltersMatched) {\n currentResult.splice(c,1);\n //break onRemoved;\n break;\n }\n \n }\n }\n }\n } \n \n } \n\n result = currentResult;\n result.notIn = instance.notIn;\n result.limit = instance.limit;\n result.find = instance.find;\n result.findOne = instance.findOne;\n result.insert = instance.insert;\n result.replace = instance.replace;\n result.update = instance.update;\n result.orderBy = instance.orderBy;\n result.max = instance.max;\n result.delete = instance.delete;\n result.toRaw = instance.toRaw;\n result.filter = instance.filter;\n\n return result\n }\n\n instance['insert'] = function (set) {\n\n var result = null;\n if ( typeof(set) !== 'object' ) {\n throw new Error('filter must be an object');\n } else {\n\n var tmpContent = Array.isArray(this) ? this : content;\n\n // Indexing;\n set._uuid = uuid.v4();\n tmpContent.push(set);\n\n result = tmpContent;\n }\n\n // chaining\n result.limit = instance.limit;\n result.find = instance.find;\n result.findOne = instance.findOne;\n result.update = instance.update;\n result.replace = instance.replace;\n result.orderBy = instance.orderBy;\n result.max = instance.max;\n result.notIn = instance.notIn;\n result.delete = instance.delete;\n result.toRaw = instance.toRaw;\n result.filter = instance.filter;\n\n return result\n }\n\n /**\n * update\n * \n * @param {object} filter\n * @param {object} set\n * \n * @return {objet} instance\n */ \n instance['update'] = function() {\n var key = '_uuid' // comparison key is _uuid by default\n , result = null\n , filters = null\n , set = null\n //, uuidSearchModeEnabled = true\n ;\n\n // comparison key : _uuid by default, but can be set to id \n if ( typeof(arguments[arguments.length-1]) == 'string' ) {\n key = arguments[arguments.length - 1];\n delete arguments[arguments.length - 1];\n --arguments.length;\n } \n \n if ( typeof(arguments[arguments.length-1]) == 'object' ) {\n set = arguments[arguments.length - 1];\n delete arguments[arguments.length - 1];\n --arguments.length\n }\n \n // if ( typeof(arguments[arguments.length-1]) == 'boolean' ) {\n // uuidSearchModeEnabled = arguments[arguments.length - 1]\n // delete arguments[arguments.length - 1];\n // --arguments.length;\n // }\n \n if (arguments.length > 0) {\n filters = arguments;\n }\n \n\n if ( typeof(filters) == 'undefined' || !filters || typeof(filters) != 'object' ) {\n throw new Error('[ Collection ][ update ] `filters` argument must be defined: Array or Filter Object(s) expected');\n }\n \n if ( typeof(set) == 'undefined' || !set || typeof(set) != 'object' ) {\n throw new Error('[ Collection ][ update ] `set` argument must be defined: Object expected');\n }\n\n // If an operation (find, insert ...) has been executed, get the previous result; if not, get the whole collection\n var foundResults = null;\n if ( Array.isArray(arguments[0]) ) {\n foundResults = arguments[0];\n } else {\n foundResults = instance.find.apply(this, arguments) || [];\n }\n \n result = Array.isArray(this) ? this : JSON.clone(content);\n if (foundResults.length > 0 ) { \n var arr = foundResults.toRaw();\n for (var a = 0, aLen = arr.length; a < aLen; ++a) { \n arr[a] = merge( JSON.clone(set), arr[a]);\n for (var r = 0, rLen = result.length; r < rLen; ++r) {\n if ( typeof(result[r][key]) == 'undefined' && key == '_uuid' && typeof(result[r]['id']) != 'undefined' ) {\n key = 'id';\n }\n \n if ( result[r][key] == arr[a][key] ) {\n result[r] = arr[a];\n break;\n }\n }\n } \n }\n\n // chaining\n result.limit = instance.limit;\n result.find = instance.find;\n result.findOne = instance.findOne;\n result.insert = instance.insert;\n result.update = instance.update;\n result.replace = instance.replace;\n result.orderBy = instance.orderBy;\n result.max = instance.max;\n result.notIn = instance.notIn;\n result.delete = instance.delete;\n result.toRaw = instance.toRaw;\n result.filter = instance.filter;\n\n return result\n }\n \n \n instance['replace'] = function() {\n var key = '_uuid' // comparison key\n , result = null\n , filters = null\n , set = null\n //, uuidSearchModeEnabled = true\n ;\n\n \n if ( typeof(arguments[arguments.length-1]) == 'string' ) {\n key = arguments[arguments.length - 1];\n delete arguments[arguments.length - 1];\n --arguments.length;\n } \n \n if ( typeof(arguments[arguments.length-1]) == 'object' ) {\n set = arguments[arguments.length - 1];\n delete arguments[arguments.length - 1];\n --arguments.length;\n }\n \n // if ( typeof(arguments[arguments.length-1]) == 'boolean' ) {\n // uuidSearchModeEnabled = arguments[arguments.length - 1]\n // delete arguments[arguments.length - 1];\n // --arguments.length;\n // }\n \n if (arguments.length > 0) {\n filters = arguments;\n }\n \n\n if ( typeof(filters) == 'undefined' || !filters || typeof(filters) != 'object' ) {\n throw new Error('[ Collection ][ update ] `filters` argument must be defined: Array or Filter Object(s) expected');\n }\n \n if ( typeof(set) == 'undefined' || !set || typeof(set) != 'object' ) {\n throw new Error('[ Collection ][ update ] `set` argument must be defined: Object expected');\n }\n\n // If an operation (find, insert ...) has been executed, get the previous result; if not, get the whole collection\n //var currentResult = JSON.clone( (Array.isArray(this)) ? this : content );\n var currentResult = null;\n var foundResults = null;\n if ( Array.isArray(arguments[0]) ) {\n foundResults = arguments[0];\n } else {\n foundResults = instance.find.apply(this, arguments) || [];\n }\n \n result = Array.isArray(this) ? this : JSON.clone(content);\n if (foundResults.length > 0 ) { \n var arr = foundResults.toRaw();\n for (var a = 0, aLen = arr.length; a < aLen; ++a) { \n arr[a] = JSON.clone(set);\n for (var r = 0, rLen = result.length; r < rLen; ++r) {\n if ( typeof(result[r][key]) == 'undefined' && key == '_uuid' && typeof(result[r]['id']) != 'undefined' ) {\n key = 'id';\n } else if (typeof(result[r][key]) == 'undefined' && key == '_uuid') {\n throw new Error('No comparison key defined !')\n } \n \n if ( result[r][key] == arr[a][key] ) {\n result[r] = arr[a];\n break;\n }\n }\n } \n }\n\n // chaining\n result.limit = instance.limit;\n result.find = instance.find;\n result.findOne = instance.findOne;\n result.insert = instance.insert;\n result.update = instance.update;\n result.replace = instance.replace;\n result.orderBy = instance.orderBy;\n result.max = instance.max;\n result.notIn = instance.notIn;\n result.delete = instance.delete;\n result.toRaw = instance.toRaw;\n result.filter = instance.filter;\n\n return result\n }\n \n /**\n * .delete({ key: 2 })\n * .delete({ name: 'Jordan' }, ''id) where id will be use as the `uuid` to compare records\n * \n * AND syntax\n * .delete({ car: 'toyota', color: 'red' })\n * \n * OR syntax\n * .delete({ car: 'toyota', color: red }, { car: 'ford' } ) // will delete all `toyota red cars` & all `ford cars`\n * \n * N.B.: will not affect current result - just returning the DIFF\n * If you\n * @param {object} filter - samme as `.find(filter)`\n * @param {string|boolean} [ uuid | disabled ] - by default, Collection is using its internal _uuid\n * If you want to delete without key comparison, disable `uuid` search mode\n * .delete({ name: 'Jordan' }, false)\n * \n * @return {array} result\n */\n instance['delete'] = function() {\n\n var result = instance.notIn.apply(this, arguments);\n\n result.limit = instance.limit;\n result.find = instance.find;\n result.findOne = instance.findOne;\n result.insert = instance.insert;\n result.update = instance.update;\n result.replace = instance.replace;\n result.orderBy = instance.orderBy;\n result.max = instance.max;\n result.notIn = instance.notIn;\n result.toRaw = instance.toRaw;\n result.filter = instance.filter;\n result.delete = this.delete;\n\n return result\n }\n\n\n var sortKeywords = [ 'asc', 'desc' ];\n /**\n * sort\n *\n * @param {object|array} filter\n * */\n instance['orderBy'] = function () {\n \n if ( typeof(arguments) == 'undefined' || arguments.length < 1)\n throw new Error('[ Collection->orderBy(filter) ] where `filter` must not be empty or null' );\n \n var filter = null;\n if ( arguments.length == 1 ) {\n filter = arguments[0];\n } else {\n // converting arguments into array\n filter = new Array(arguments.length);\n for (var f = 0, fLen = filter.length; f < fLen; ++f) {\n filter[f] = arguments[f]\n }\n }\n\n var variableContent = (Array.isArray(this)) ? this : JSON.clone(content);\n return sortResult(filter, variableContent.toRaw())\n }\n \n /**\n * max\n * E.g: \n * myCollection.max({ order: 'not null'})\n * => 5\n * myCollection.max({ createAt: 'not null'})\n * => '2021-12-31T23:59:59'\n * myCollection.max({ firstName: 'not null'})\n * => 'Zora'\n * \n * @param {object|array} filter\n * \n * @return {number|date|string}\n * */\n instance['max'] = function () {\n if ( typeof(arguments) == 'undefined' || arguments.length < 1)\n throw new Error('[ Collection->max(filter) ] where `filter` must not be empty or null' );\n \n var filter = null;\n if ( \n arguments.length > 1\n || Array.isArray(arguments[0])\n || typeof(arguments[0]) == 'object' && arguments[0].count() > 1\n ) {\n throw new Error('[ Collection->max(filter) ] only accept one filter length, and fileter count must be equal to 1' );\n }\n filter = arguments[0];\n try {\n var key = Object.keys(filter)[0];\n var subFilter = {};\n subFilter[key] = 'desc';\n return instance['find'](filter).orderBy(subFilter).limit(1)[0][key];\n } catch (err) {\n throw err\n }\n }\n\n /**\n * sortResult\n * ref.:\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare#Browser_compatibility\n *\n * e.g.:\n * .orderBy({ name: 'asc' })\n *\n * // overriding filters -> last filter is always right\n * .orderBy([ { updatedAt : 'desc'}, { name: 'asc' } ])\n * \n * // sorting boolean \n * .orderBy({ isActive: 'desc'}) => will display all active(TRUE) first\n * NB.: Boolean are 0 (FALSE) or 1 (TRUE)\n * \n * // combining filters -> the first one is always right\n * .orderBy({ updatedAt : 'desc'}, { name: 'asc' })\n *\n * @param {object|array} filter\n * */\n var sortResult = function (filter, content) {\n if ( typeof(filter) != 'object') {\n throw new Error('`filter` parametter must be an object or an array')\n }\n\n var condition = filter.count()\n , sortOp = {}\n , multiSortOp = null\n , sortRecursive = null\n , key = null\n , prop = null\n , result = []\n ;\n\n if (condition == 0) return null;\n\n\n // asc\n sortOp['asc'] = function (prop, content) {\n\n var mapped = content.map(function(obj, i) {\n var _m = {};\n _m.index = i;\n _m[prop] = obj[prop];\n return _m;\n });\n \n mapped.sort(function onAscSort(a, b) { \n \n \n var _compare = function(a, b) {\n // handle booleans\n if ( /^(true|false)$/i.test(a) ) {\n a = ( /true/i.test(a) ) ? 1 : 0;\n }\n \n if ( /^(true|false)$/i.test(b) ) {\n b = ( /true/i.test(b) ) ? 1 : 0;\n }\n \n \n if ( typeof(a) == 'string' && a != '' || typeof(b) == 'string' ) {\n \n if ( typeof(a) == 'number' ) {\n a = ''+a; // cast to string\n } \n if ( typeof(b) == 'number' ) {\n b = ''+b; // cast to string\n } \n \n return a.localeCompare(b, undefined, {sensitivity: 'case', caseFirst: 'upper'})\n }\n \n if (a > b) {\n return 1;\n }\n if (a < b) {\n return -1;\n }\n // a must be equal to b\n return 0; \n }\n \n \n if ( typeof(a) == 'object' ) {\n return _compare(a[prop], b[prop])\n }\n \n return _compare(a, b)\n \n });\n \n return mapped.map(function(m, index, result){\n return content[m.index];\n });\n }\n\n // desc\n sortOp['desc'] = function (prop, content) {\n return sortOp['asc'](prop, content).reverse()\n }\n\n multiSortOp = function(content, filter) {\n \n var props = [], keys = [];\n \n if ( Array.isArray(filter) ) {\n for (var f = 0, fLen = filter.length; f < fLen; ++f) {\n props[f] = Object.keys(filter[f])[0];\n keys[f] = filter[f][ props[f]] ; \n }\n } else {\n var f = 0;\n for (var flt in filter) {\n props[f] = flt;\n keys[f] = filter[flt] ; \n ++f;\n }\n }\n \n \n\n sortRecursive = function(a, b, columns, order_by, index) {\n\n var direction = order_by[index] == 'desc' ? 1 : 0;\n\n var res = null, x = null, y = null;\n\n if ( typeof(a[columns[index]]) == 'string' && a[columns[index]] != '' ) {\n\n res = a[columns[index]].localeCompare(b[columns[index]]);\n\n if ( direction == 0 && res != 0 ) {\n return res < 0 ? -1 : 1\n } else if (res != 0) {\n return res < 0 ? 1 : -1\n }\n \n // a must be equal to b\n return columns.length - 1 > index ? sortRecursive(a, b, columns, order_by, index + 1) : 0;\n\n } else if (typeof (a[columns[index]]) == 'number' || typeof(b[columns[index]]) == 'number' ) {\n\n res = (''+ a[columns[index]]).localeCompare((''+ b[columns[index]]), undefined, { numeric: true });\n\n if (direction == 0 && res != 0) {\n return res < 0 ? -1 : 1\n } else if (res != 0) {\n return res < 0 ? 1 : -1\n }\n\n // a must be equal to b\n return columns.length - 1 > index ? sortRecursive(a, b, columns, order_by, index + 1) : 0;\n\n } else if ( typeof(a[columns[index]]) == 'boolean' || typeof (b[columns[index]]) == 'boolean' ) {\n\n if ( typeof(a[columns[index]]) == 'boolean' ) {\n x = (a[columns[index]]) ? 1 : 0;\n }\n\n if ( typeof(b[columns[index]]) == 'boolean' ) {\n y = (b[columns[index]]) ? 1 : 0;\n }\n\n if (x > y) {\n return direction == 0 ? 1 : -1;\n }\n\n if (x < y) {\n return direction == 0 ? -1: 1;\n }\n\n // a must be equal to b\n return columns.length - 1 > index ? sortRecursive(a, b, columns, order_by, index + 1) : 0;\n\n } else {\n\n if (a[columns[index]] > b[columns[index]]) {\n return direction == 0 ? 1 : -1;\n }\n\n if (a[columns[index]] < b[columns[index]]) {\n return direction == 0 ? -1 : 1;\n }\n // a must be equal to b\n return columns.length - 1 > index ? sortRecursive(a, b, columns, order_by, index + 1) : 0;\n }\n }\n\n return content.sort(function onMultiSort(a, b) {\n return sortRecursive(a, b, props, keys, 0);\n });\n // return mapped.map(function(m, index, result){\n // return content[m.index];\n // });\n }\n\n if ( Array.isArray(filter) || filter.count() > 1 ) {\n \n result = multiSortOp(content, filter);\n \n } else {\n \n prop = Object.keys(filter)[0];\n key = filter[prop];\n\n result = sortOp[key](prop, content);\n }\n\n\n\n // chaining\n result.find = instance.find;\n result.findOne = instance.findOne;\n result.limit = instance.limit;\n result.notIn = instance.notIn;\n result.insert = instance.insert;\n result.update = instance.update;\n result.replace = instance.replace;\n result.delete = instance.delete;\n result.orderBy = instance.orderBy;\n result.max = instance.max;\n result.toRaw = instance.toRaw;\n result.filter = instance.filter;\n \n return result\n };\n\n /**\n * toRaw\n * Transform result into a clean format (without _uuid)\n *\n * @return {array} result\n * */\n instance['toRaw'] = function() {\n\n var result = ( Array.isArray(this) ) ? this : content;\n // cleanup\n for (var i = 0, len = result.length; i < len; ++i) {\n if (result[i]._uuid)\n delete result[i]._uuid;\n }\n\n return JSON.clone(result);\n }\n \n /**\n * filter\n * Reduce record propName\n * @param {string|array} filter\n * e.g: 'id'\n * e.g: ['id', 'name']\n *\n * @return {array} rawFilteredResult\n * */\n instance['filter'] = function(filter) {\n \n if ( typeof(filter) == 'undefined' ) {\n throw new Error('`filter` parametter must be a string or an array.');\n }\n var result = ( Array.isArray(this) ) ? this : content;\n if ( !result.length ) {\n return []\n }\n var i = 0, len = result.length;\n var rawFilteredResult = [], fCount = 0;\n \n if ( Array.isArray(filter) ) {\n var f = null, fLen = filter.length, wrote = null;\n for (; i < len; ++i) {\n wrote = false;\n f = 0;\n for (; f < fLen; ++f) {\n if ( typeof(result[i][ filter[f] ]) != 'undefined' ) {\n if ( typeof(rawFilteredResult[fCount]) == 'undefined' ) {\n rawFilteredResult[fCount] = {}\n }\n rawFilteredResult[fCount][ filter[f] ] = result[i][ filter[f] ];\n wrote = true;\n }\n }\n if (wrote)\n ++fCount;\n }\n } else {\n for (; i < len; ++i) {\n if ( typeof(result[i][filter]) != 'undefined' ) {\n if ( typeof(rawFilteredResult[fCount]) == 'undefined' ) {\n rawFilteredResult[fCount] = {}\n }\n rawFilteredResult[fCount][filter] = result[i][filter];\n ++fCount;\n }\n }\n } \n\n return JSON.clone(rawFilteredResult);\n }\n \n \n return instance;\n};\n\nif ( ( typeof(module) !== 'undefined' ) && module.exports ) {\n // Publish as node.js module\n module.exports = Collection\n} else if ( typeof(define) === 'function' && define.amd) {\n // Publish as AMD module\n define('utils/collection',[],function() { return Collection })\n};\n",
40
40
  "/**\n * FormValidatorUtil\n *\n * Dependencies:\n * - utils/helpers\n * - utils/helpers/dateFormat\n * - utils/merge\n * - utils/routing (for API calls)\n *\n * @param {object} data\n * @param {object} [ $fields ] - isGFFCtx only\n * @param {object} [ xhrOptions ] - isGFFCtx only\n * @param {object} [ fieldsSet ] - isGFFCtx only; required for when ginaFormLiveCheckEnabled\n * */\nfunction FormValidatorUtil(data, $fields, xhrOptions, fieldsSet) {\n\n var isGFFCtx = ( ( typeof(module) !== 'undefined' ) && module.exports ) ? false : true;\n\n // if (isGFFCtx && !$fields )\n // throw new Error('No `Validator` instance found.\\nTry:\\nvar FormValidator = require(\"gina/validator\"):\\nvar formValidator = new FormValidator(...);')\n \n var merge = (isGFFCtx) ? require('utils/merge') : require('../../../../../lib/merge');\n var helpers = (isGFFCtx) ? {} : require('../../../../../helpers');\n var dateFormat = (isGFFCtx) ? require('helpers/dateFormat') : helpers.dateFormat;\n var routing = (isGFFCtx) ? require('utils/routing') : require('../../../../../lib/routing');\n \n var hasUserValidators = function() {\n \n var _hasUserValidators = false, formsContext = null;\n // backend validation check\n if (!isGFFCtx) {\n // TODO - retrieve bakcend forms context\n formsContext = getContext('gina').forms || null;\n } else if (isGFFCtx && typeof(gina.forms) != 'undefined') {\n formsContext = gina.forms\n }\n if ( formsContext && typeof(formsContext.validators) != 'undefined' ) {\n _hasUserValidators = true\n }\n return _hasUserValidators;\n } \n /**@js_externs local*/\n var local = {\n 'errors': {},\n 'keys': {\n '%l': 'label', // %l => label: needs `data-gina-form-field-label` attribute (frontend only)\n '%n': 'name', // %n => field name\n '%s': 'size' // %s => length\n },\n 'errorLabels': {},\n 'data': {}, // output to send\n 'excluded': []\n };\n\n local.errorLabels = {\n 'is': 'Condition not satisfied',\n 'isEmail': 'A valid email is required',\n 'isRequired': 'Cannot be left empty',\n 'isBoolean': 'Must be a valid boolean',\n 'isNumber': 'Must be a number: allowed values are integers or floats',\n 'isNumberLength': 'Must contain %s characters',\n 'isNumberMinLength': 'Should be at least %s characters',\n 'isNumberMaxLength': 'Should not be more than %s characters',\n 'isInteger': 'Must be an integer',\n 'isIntegerLength': 'Must have %s characters',\n 'isIntegerMinLength': 'Should be at least %s characters',\n 'isIntegerMaxLength': 'Should not be more than %s characters',\n 'toInteger': 'Could not be converted to integer',\n 'isFloat': 'Must be a proper float',\n 'isFloatException': 'Float exception found: %n',\n 'toFloat': 'Could not be converted to float',\n 'toFloatNAN': 'Value must be a valid number',\n 'isDate': 'Must be a valid Date',\n 'isString': 'Must be a string',\n 'isStringLength': 'Must have %s characters',\n 'isStringMinLength': 'Should be at least %s characters',\n 'isStringMaxLength': 'Should not be more than %s characters',\n 'isJsonWebToken': 'Must be a valid JSON Web Token',\n 'query': 'Must be a valid response',\n 'isApiError': 'Condition not satisfied'\n };\n var self = null;\n if (!data) {\n throw new Error('missing data param')\n } else {\n // cloning\n self = merge( JSON.clone(data), self );\n local.data = merge( JSON.clone(data), local.data);\n }\n \n var getElementByName = function($form, name) { // frontend only\n var $foundElement = null;\n for (let f in fieldsSet) {\n if (fieldsSet[f].name !== name) continue;\n \n $foundElement = new DOMParser()\n .parseFromString($form.innerHTML , 'text/html')\n .getElementById( fieldsSet[f].id );\n break;\n }\n if ($foundElement)\n return $foundElement;\n \n throw new Error('Field `'+ name +'` not found in fieldsSet');\n }\n \n /**\n * bufferToString - Convert Buffer to String\n * Will apply `Utf8Array` to `String`\n * @param {array} arrayBuffer \n */\n var bufferToString = function(arrayBuffer) {\n // if (!isGFFCtx) {\n \n // return Buffe\n // }\n var out = null\n , i = null\n , len = null\n , c = null\n ;\n var char2 = null, char3 = null;\n\n out = '';\n len = arrayBuffer.length;\n i = 0;\n while(i < len) {\n c = arrayBuffer[i++];\n switch (c >> 4) { \n case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:\n // 0xxxxxxx\n out += String.fromCharCode(c);\n break;\n case 12: case 13:\n // 110x xxxx 10xx xxxx\n char2 = arrayBuffer[i++];\n out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));\n break;\n case 14:\n // 1110 xxxx 10xx xxxx 10xx xxxx\n char2 = arrayBuffer[i++];\n char3 = arrayBuffer[i++];\n out += String.fromCharCode(((c & 0x0F) << 12) |\n ((char2 & 0x3F) << 6) |\n ((char3 & 0x3F) << 0));\n break;\n }\n }\n\n return out;\n };\n \n // TODO - One method for the front, and one for the server\n var queryFromFrontend = function(options, errorMessage) {\n var errors = self[this['name']]['errors'] || {}; \n var id = this.target.id || this.target.getAttribute('id');\n \n \n // stop if \n // - previous error detected \n if ( !self.isValid() ) { \n console.debug('stopping on errors ...');\n triggerEvent(gina, this.target, 'asyncCompleted.' + id, self[this['name']]);\n //return self[this.name];\n return;\n }\n \n var testedValue = this.target.dataset.ginaFormValidatorTestedValue;\n console.debug('[ '+ this['name'] +' ]', 'TESTED VALUE -> ' + this.value +' vs '+ testedValue);\n var _evt = 'asyncCompleted.' + id;\n var currentFormId = this.target.form.getAttribute('id');\n var cachedErrors = (\n typeof(gina.validator) != 'undefined'\n && typeof(gina.validator.$forms[currentFormId]) != 'undefined'\n && typeof(gina.validator.$forms[currentFormId].cachedErrors) != 'undefined'\n )\n ? gina.validator.$forms[currentFormId].cachedErrors \n : null;\n if ( !testedValue || typeof(testedValue) == 'undefined' || testedValue !== this.value ) {\n this.target.dataset.ginaFormValidatorTestedValue = this.value;\n // remove cachedErrors\n if ( \n cachedErrors \n && typeof(cachedErrors[this.name]) != 'undefined'\n && typeof(cachedErrors[this.name].query) != 'undefined'\n ) {\n delete cachedErrors[this.name].query;\n if ( \n typeof(gina.validator.$forms[currentFormId]) != 'undefined'\n &&\n typeof(gina.validator.$forms[currentFormId].errors) != 'undefined'\n ) {\n delete gina.validator.$forms[currentFormId].errors.query;\n }\n \n }\n } else if (testedValue === this.value) {\n // not resending to backend, but in case of cached errors, re display same error message\n var hasCachedErrors = false; \n if ( \n cachedErrors \n && typeof(cachedErrors[this.name]) != 'undefined'\n && typeof(cachedErrors[this.name].query) != 'undefined' \n && typeof(cachedErrors[this.name].query[this.value]) != 'undefined' \n ) {\n this.error = errorMessage = cachedErrors[this.name].query[this.value].slice(0);\n hasCachedErrors = true;\n }\n errors['query'] = replace( this.error || errorMessage || local.errorLabels['query'], this);\n \n if (hasCachedErrors) {\n this['errors'] = errors;\n this.valid = false;\n }\n // Do not remove this test \n if ( typeof( gina.events[_evt]) != 'undefined' ) {\n triggerEvent(gina, this.target, _evt, self[this['name']]);\n } \n \n return self[this.name];\n }\n //console.debug('Did not return !!!');\n \n var xhr = null, _this = this;\n // setting up AJAX\n if (window.XMLHttpRequest) { // Mozilla, Safari, ...\n xhr = new XMLHttpRequest();\n } else if (window.ActiveXObject) { // IE\n try {\n xhr = new ActiveXObject(\"Msxml2.XMLHTTP\");\n } catch (e) {\n try {\n xhr = new ActiveXObject(\"Microsoft.XMLHTTP\");\n }\n catch (e) {}\n }\n }\n \n // forcing to sync mode\n var queryOptions = { isSynchrone: false, headers: {} }; \n var queryData = options.data || null, strData = null;\n var isInlineValidation = (/^true$/i.test(this.target.form.dataset.ginaFormLiveCheckEnabled)) ? true : false; // TRUE if liveCheckEnabled\n \n // replace placeholders by field values\n strData = JSON.stringify(queryData);\n if ( /\\$/.test(strData) ) {\n var variables = strData.match(/\\$[-_\\[\\]a-z 0-9]+/g) || [];\n var value = null, key = null; \n for (let i = 0, len = variables.length; i < len; i++) {\n key = variables[i].replace(/\\$/g, '');\n re = new RegExp(\"\\\\\"+ variables[i].replace(/\\[|\\]/g, '\\\\$&'), \"g\");\n value = local.data[key] || null;\n if (!value && isInlineValidation) {\n // Retrieving live value instead of using fieldsSet.value\n value = getElementByName(this.target.form, key).value;\n }\n \n strData = strData.replace( re, value );\n }\n }\n // cleanup before sending\n queryData = strData.replace(/\\\\\"/g, ''); \n // TODO - support regexp for validIf\n var validIf = ( typeof(options.validIf) == 'undefined' ) ? true : options.validIf;\n \n queryOptions = merge(queryOptions, options, xhrOptions);\n delete queryOptions.data;\n delete queryOptions.validIf;\n \n var enctype = queryOptions.headers['Content-Type'];\n var result = null\n , $target = this.target\n //, id = $target.getAttribute('id')\n ;\n id = $target.getAttribute('id')\n \n // checking url\n if (!/^http/.test(queryOptions.url) && /\\@/.test(queryOptions.url) ) {\n try {\n var route = routing.getRoute(queryOptions.url);\n queryOptions.url = route.toUrl();\n } catch (routingError) {\n throw routingError;\n }\n }\n \n if ( queryOptions.withCredentials ) {\n if ('withCredentials' in xhr) {\n // XHR for Chrome/Firefox/Opera/Safari.\n if (queryOptions.isSynchrone) {\n xhr.open(queryOptions.method, queryOptions.url, queryOptions.isSynchrone)\n } else {\n xhr.open(queryOptions.method, queryOptions.url)\n }\n } else if ( typeof XDomainRequest != 'undefined' ) {\n // XDomainRequest for IE.\n xhr = new XDomainRequest();\n // if (queryOptions.isSynchrone) {\n // xhr.open(queryOptions.method, queryOptions.url, queryOptions.isSynchrone);\n // } else {\n xhr.open(queryOptions.method, queryOptions.url);\n // } \n } else {\n // CORS not supported.\n xhr = null;\n result = 'CORS not supported: the server is missing the header `\"Access-Control-Allow-Credentials\": true` ';\n //triggerEvent(gina, $target, 'error.' + id, result);\n throw new Error(result);\n }\n \n if ( typeof(queryOptions.responseType) != 'undefined' ) {\n /**\n * Note: We expect to remove support for synchronous use of XMLHTTPRequest() during page unloads in Chrome in version 88, \n * scheduled to ship in January 2021.\n * The XMLHttpRequest2 spec was recently changed to prohibit sending a synchronous request when XMLHttpRequest.responseType\n */\n xhr.responseType = queryOptions.responseType;\n } else {\n xhr.responseType = '';\n }\n\n xhr.withCredentials = true;\n } else {\n if (queryOptions.isSynchrone) {\n xhr.open(queryOptions.method, queryOptions.url, queryOptions.isSynchrone)\n } else {\n xhr.open(queryOptions.method, queryOptions.url)\n }\n }\n \n // setting up headers - all but Content-Type ; it will be set right before .send() is called\n for (var hearder in queryOptions.headers) {\n if (hearder == 'Content-Type' && typeof (enctype) != 'undefined' && enctype != null && enctype != '')\n continue;\n\n xhr.setRequestHeader(hearder, queryOptions.headers[hearder]);\n } \n if (typeof (enctype) != 'undefined' && enctype != null && enctype != '') {\n xhr.setRequestHeader('Content-Type', enctype);\n }\n \n if (xhr) {\n \n xhr.onload = function () { \n \n var onResult = function(result) {\n \n _this.value = local['data'][_this.name] = (_this.value) ? _this.value.toLowerCase() : _this.value;\n \n var isValid = result.isValid || false;\n if (validIf != isValid) {\n isValid = false; \n } else {\n isValid = true;\n }\n self[_this['name']].valid = isValid;\n var errors = self[_this['name']]['errors'] || {};\n \n var errorFields = ( typeof(result.error) != 'undefined' && typeof(result.fields) != 'undefined' ) ? result.fields : {};\n \n if (errorFields.count() > 0 && !isValid || !isValid) {\n \n if (!isValid) {\n var systemError = null;\n if ( typeof(errorFields[_this.name]) != 'undefined') {\n local.errorLabels['query'] = errorFields[_this.name]; \n } else if ( typeof(result.error) != 'undefined' && /^5/.test(result.status) ) {\n // system error\n //console.debug('found system error: ', result);\n systemError = result.error;\n } \n errors['query'] = replace(systemError || _this['error'] || options['error'] || local.errorLabels['query'], _this);\n console.debug('query error detected !! ', result);\n }\n \n if ( !errors['query'] && _this.value == '' ) {\n isValid = true;\n }\n }\n \n // if error tagged by a previous validation, remove it when isValid == true \n if ( isValid && typeof(errors['query']) != 'undefined' ) {\n delete errors['query'];\n }\n \n // To handle multiple errors from backend\n // for (var f in errorFields.length) {\n // if ( !errors['query'] && _this.value == '' ) {\n // isValid = true;\n // }\n \n // if (!isValid) {\n // errors['query'] = replace(_this['error'] || local.errorLabels['query'], _this)\n // }\n // // if error tagged by a previous validation, remove it when isValid == true \n // else if ( isValid && typeof(errors['query']) != 'undefined' ) {\n // delete errors['query'];\n // }\n // }\n \n _this.valid = isValid;\n var cachedErrors = gina.validator.$forms[_this.target.form.getAttribute('id')].cachedErrors || {};\n if ( errors.count() > 0 ) {\n \n _this['errors'] = errors;\n if ( typeof(self[_this['name']].errors) == 'undefined' ) {\n self[_this['name']].errors = {};\n }\n \n self[_this['name']].errors = merge(self[_this['name']].errors, errors);\n \n if ( typeof(errors.query) != 'undefined' && errors.query ) {\n \n if ( typeof(cachedErrors[_this.name]) == 'undefined' ) {\n cachedErrors[_this.name] = {}\n }\n if ( typeof(cachedErrors[_this.name].query) == 'undefined' ) {\n cachedErrors[_this.name].query = {}\n }\n \n cachedErrors[_this.name].query[_this.value] = errors.query.slice(0);\n }\n \n var errClass = _this.target.getAttribute('data-gina-form-errors');\n if ( !/query/.test(errClass) ) {\n if ( !errClass || errClass =='' ) {\n errClass = 'query' \n } else {\n errClass +=' query'\n }\n _this.target.setAttribute('data-gina-form-errors', errClass);\n }\n } else if ( \n typeof(cachedErrors[_this.name]) != 'undefined'\n && typeof(cachedErrors[_this.name].query) != 'undefined'\n && typeof(cachedErrors[_this.name].query[_this.value]) != 'undefined'\n ) {\n delete cachedErrors[_this.name].query[_this.value];\n }\n \n var id = _this.target.id || _this.target.getAttribute('id');\n console.debug('prematurely completed event `'+ 'asyncCompleted.' + id +'`');\n return triggerEvent(gina, _this.target, 'asyncCompleted.' + id, self[_this['name']]);\n }\n \n try {\n result = this.responseText;\n var contentType = this.getResponseHeader(\"Content-Type\");\n if ( /\\/json/.test( contentType ) ) {\n result = JSON.parse(this.responseText);\n \n if ( typeof(result.status) == 'undefined' )\n result.status = this.status;\n \n //triggerEvent(gina, $target, 'success.' + id, result); \n return onResult(result)\n } else {\n result = { 'status': xhr.status, 'message': '' };\n if ( /^(\\{|\\[)/.test( xhr.responseText ) ) {\n try {\n result = merge( result, JSON.parse(xhr.responseText) );\n } catch (err) {\n result = merge(result, err);\n }\n }\n return onResult(result);\n }\n } catch (err) {\n throw err;\n } \n }\n \n if (data) {\n xhr.send( queryData ); // stringyfied\n } else {\n xhr.send();\n } \n }\n }\n \n /**\n * queryFromBackend\n * \n * \n * @param {object} options \n * @param {object} request \n * @param {object} response \n * @param {callback} next\n * \n * \n */\n var queryFromBackend = async function(options, request, response, next) {\n var Config = require(_(GINA_FRAMEWORK_DIR +'/core/config.js', true));\n var config = new Config().getInstance();\n \n var opt = null\n //appConf.proxy.<bundle>;\n , rule = null\n , bundle = null\n , currentBundle = getContext('bundle')\n ;\n // trying to retrieve proxy conf\n if ( /\\@/.test(options.url) ) {\n var attr = options.url.split(/@/); \n rule = attr[0];\n bundle = attr[1];\n var proxyConf = getConfig( currentBundle, 'app' ).proxy;\n try {\n if (config.bundle !== bundle) { // ignore if same bundle\n // getting proxy conf when available\n opt = getConfig( currentBundle, 'app' ).proxy[bundle];\n } \n } catch (proxyError) {\n throw new Error('Could not retrieve `proxy` configuration for bundle `'+ bundle +'`. Please check your `/config/app.json`.\\n'+proxyError.stack);\n }\n \n attr = null;\n } else {\n // TODO - handle else; when it is an external domain/url\n throw new Error('external url/domain not handled at this moment, please contact us if you need support for it.')\n }\n var route = JSON.clone(routing.getRoute(options.url, options.data));\n var env = config.env;\n var conf = config[bundle][env]; \n if (!opt) { // setup opt by default if no proxy conf found\n if (config.bundle == bundle) {\n var credentials = getConfig( currentBundle, 'settings' ).server.credentials;\n options.ca = credentials.ca || null;\n options.hostname = conf.server.scheme +'://'+ conf.host;\n options.port = conf.port[conf.server.protocol][conf.server.scheme];\n options.protocol = conf.server.protocol;\n options.rejectUnauthorized = false;\n }\n opt = { \n \"ca\" : options.ca,\n \"hostname\" : options.hostname, \n \"port\" : options.port, \n \"path\" : options.path\n };\n \n if ( typeof(options.protocol) != 'undefined' ) {\n opt.protocol = options.protocol\n }\n if ( typeof(options.rejectUnauthorized) != 'undefined' ) {\n opt.rejectUnauthorized = options.rejectUnauthorized\n }\n }\n \n /**\n * BO routing configuration\n * Attention: this portion of code is from `router.js`\n * Any modification on this part must be reflected on `router.js`\n */\n // default param setting\n var params = {\n method : route.method,\n requirements : route.requirements,\n namespace : route.namespace || undefined,\n url : unescape(route.url), /// avoid %20\n rule : rule + '@' + bundle,\n param : JSON.clone(route.param),\n middleware : JSON.clone(route.middleware),\n bundle : route.bundle,\n isXMLRequest : request.isXMLRequest,\n isWithCredentials : request.isWithCredentials\n };\n \n var templateName = params.rule.replace('\\@'+ bundle, '') || '_common';\n var routeHasViews = ( typeof(conf.content.templates) != 'undefined' ) ? true : false;\n var controllerOptions = {\n // view namespace first\n template: (routeHasViews) ? conf.content.templates[templateName] || conf.content.templates._common : undefined,\n // namespace : params.param.namespace || namespace,\n //control : route.param.control,\n // controller : controllerFile,\n //controller: '<span class=\"gina-bundle-name\">' + bundle +'</span>/controllers/controller.js',\n //file: route.param.file, // matches rule name by default\n //bundle : bundle,//module\n // bundlePath : conf.bundlesPath + '/' + bundle,\n // rootPath : self.executionPath,\n // We don't want to keep original conf untouched\n conf : JSON.clone(conf),\n //instance: self.serverInstance,\n //template: (routeHasViews) ? conf.content.templates[templateName] : undefined,\n //isUsingTemplate: local.isUsingTemplate,\n cacheless: conf.cacheless //,\n //path: params.param.path || null, // user custom path : namespace should be ignored | left blank\n //assets: {}\n };\n \n controllerOptions = merge(controllerOptions, params); \n \n // BO - Template outside of namespace fix added on 2021-08-19\n // We want to keep original conf untouched\n controllerOptions.conf = JSON.clone(conf);\n controllerOptions.conf.content.routing[controllerOptions.rule].param = params.param;\n // inheriting from _common\n if (\n controllerOptions.template\n && typeof(controllerOptions.template.ginaLoader) == 'undefined'\n ) {\n controllerOptions.template.ginaLoader = controllerOptions.conf.content.templates._common.ginaLoader;\n } \n controllerOptions.conf.content.routing[controllerOptions.rule].param = params.param;\n delete controllerOptions.middleware;\n delete controllerOptions.param;\n delete controllerOptions.requirements;\n // EO - Template outside of namespace\n /**\n * EO routing configuration\n */\n \n var Controller = require(_(GINA_FRAMEWORK_DIR +'/core/controller/controller.js'), true);\n var controller = new Controller(controllerOptions);\n controller.name = route.param.control; \n //controller.serverInstance = serverInstance;\n controller.setOptions(request, response, next, controllerOptions);\n \n \n var data = ( typeof(options.data) == 'object' && options.data.count() > 0 )\n ? options.data\n : {}; \n // inherited data from current query asking for validation\n var urlParams = '';\n if ( /^get|delete|put$/i.test(options.method) ) {\n urlParams += '?';\n var i = 0;\n for (let p in data) {\n if (i > 0) {\n urlParams += '&';\n }\n let val = (typeof(data[p]) == 'object') ? encodeURIComponent(JSON.stringify(data[p])) : data[p];\n urlParams += p +'='+ val;\n i++;\n }\n }\n opt.method = options.method;\n //opt.path = route.url + urlParams;\n opt.path = route.url;\n \n var util = require('util');\n var promisify = util.promisify;\n var result = { isValid: false }, err = false;\n \n await promisify(controller.query)(opt, data)\n .then(function onResult(_result) {\n result = _result;\n })\n .catch(function onResultError(_err) {\n err = _err;\n });\n if (err) {\n //throw err;\n console.error(err);\n result.error = err;\n } \n return result;\n };\n \n /**\n * query\n */\n var query = null;\n if (isGFFCtx) {\n query = queryFromFrontend;\n } else {\n query = queryFromBackend;\n }\n\n\n /**\n * addField\n * Add field to the validation context\n * @param {string} el \n * @param {string|boolean|number|object} [value] \n */\n var addField = function(el, value) { \n var val = null, label = null;\n \n if ( typeof(self[el]) == 'undefined' && typeof(value) != 'undefined' ) {\n self[el] = val = value;\n }\n \n if ( typeof(self[el]) == 'object' ) {\n try {\n val = JSON.parse( JSON.stringify( self[el] ))\n } catch (err) {\n val = self[el]\n }\n } else {\n val = self[el]\n }\n\n label = '';\n if ( isGFFCtx && typeof($fields) != 'undefined' ) { // frontend only\n label = $fields[el].getAttribute('data-gina-form-field-label') || '';\n }\n\n // keys are stringyfied because of the compiler !!!\n self[el] = {\n 'target': (isGFFCtx && typeof($fields) != 'undefined') ? $fields[el] : null,\n 'name': el,\n 'value': val,\n 'valid': false,\n // is name by default, but you should use setLabe(name) to change it if you need to\n 'label': label,\n // check as field to exclude while sending datas to the model\n 'exclude': false\n };\n\n /**\n *\n * is(condition) -> validate if value matches `condition`\n *\n * When entered in a JSON rule, you must double the backslashes\n *\n * e.g.:\n * \"/\\\\D+/\" -> like [^0-9]\n * \"!/^\\\\\\\\s+/\" -> not starting by white space allow\n * \"/^[0-9]+$/\" -> only numbers\n * \"$field === $fieldOther\" -> will be evaluated\n *\n * @param {object|string} condition - RegExp object, or condition to eval, or eval result\n * @param {string} [errorMessage] - error message\n * @param {string} [errorStack] - error stack\n *\n * */\n self[el]['is'] = function(condition, errorMessage, errorStack) {\n var isValid = false;\n var alias = ( typeof(window) != 'undefined' && typeof(window._currentValidatorAlias) != 'undefined' ) ? window._currentValidatorAlias : 'is';\n if ( typeof(window) != 'undefined' && window._currentValidatorAlias)\n delete window._currentValidatorAlias;\n \n var errors = self[this['name']]['errors'] || {}; \n local.data[this.name] = self[this.name].value;\n \n if ( \n typeof(errors['isRequired']) == 'undefined'\n && this.value == ''\n && !/^false$/i.test(this.value) \n && this.value != 0 \n ||\n !errors['isRequired'] \n && this.value == ''\n && !/^false$/i.test(this.value)\n && this.value != 0\n ) {\n isValid = true;\n } else if (!errors['isRequired'] && typeof(this.value) == 'string' && this.value == '') {\n isValid = true;\n }\n \n if ( !isValid && /^(true|false)$/i.test(condition) ) { // because it can be evaluated on backend validation\n isValid = condition;\n } else if (!isValid) {\n var re = null, flags = null;\n // Fixed on 2021-03-13: $variable now replaced with real value beafore validation\n if ( /[\\!\\=>\\>\\<a-z 0-9]+/i.test(condition) ) {\n var variables = condition.match(/\\${0}[-_,.\\[\\]a-z0-9]+/ig); // without space(s) \n if (variables && variables.length > 0) {\n var compiledCondition = condition;\n for (var i = 0, len = variables.length; i < len; ++i) {\n // $varibale comparison\n if ( typeof(self[ variables[i] ]) != 'undefined' && variables[i]) {\n re = new RegExp(\"\\\\$\"+ variables[i] +\"(?!\\\\S+)\", \"g\");\n if ( self[ variables[i] ].value == \"\" ) {\n compiledCondition = compiledCondition.replace(re, '\"\"');\n } else if ( typeof(self[ variables[i] ].value) == 'string' ) {\n compiledCondition = compiledCondition.replace(re, '\"'+ self[ variables[i] ].value +'\"');\n } else {\n compiledCondition = compiledCondition.replace(re, self[ variables[i] ].value);\n }\n }\n }\n \n try {\n // security checks\n compiledCondition = compiledCondition.replace(/(\\(|\\)|return)/g, '');\n if ( /^\\//.test(compiledCondition) ) {\n isValid = eval(compiledCondition + '.test(\"' + this.value + '\")')\n } else {\n isValid = eval(compiledCondition)\n }\n \n } catch (err) {\n throw new Error(err.stack||err.message)\n }\n }\n } else if ( condition instanceof RegExp ) {\n\n isValid = condition.test(this.value) ? true : false;\n\n } else if( typeof(condition) == 'boolean') {\n\n isValid = (condition) ? true : false;\n\n } else {\n try {\n // TODO - motif /gi to pass to the second argument\n if ( /\\/(.*)\\//.test(condition) ) {\n re = condition.match(/\\/(.*)\\//).pop();\n flags = condition.replace('/' + re + '/', '');\n\n isValid = new RegExp(re, flags).test(this.value)\n } else {\n isValid = eval(condition);\n }\n \n //valid = new RegExp(condition.replace(/\\//g, '')).test(this.value)\n } catch (err) {\n throw new Error(err.stack||err.message)\n }\n }\n }\n\n if (!isValid) {\n errors[alias] = replace(this.error || errorMessage || local.errorLabels[alias], this);\n if ( typeof(errorStack) != 'undefined' )\n errors['stack'] = errorStack;\n }\n // if error tagged by a previous vlaidation, remove it when isValid == true \n else if ( isValid && typeof(errors[alias]) != 'undefined' ) {\n delete errors[alias];\n //delete errors['stack'];\n }\n\n this.valid = isValid;\n if ( errors.count() > 0 )\n this['errors'] = errors;\n\n \n return self[this.name]\n }\n \n self[el]['set'] = function(value) {\n this.value = local['data'][this.name] = value;\n // html \n this.target.setAttribute('value', value);\n // Todo : select and radio case to apply change\n \n return self[this.name]\n }\n\n self[el]['isEmail'] = function() {\n\n\n this.value = local['data'][this.name] = (this.value) ? this.value.toLowerCase() : this.value;\n // Apply on current field upper -> lower\n if ( \n isGFFCtx\n && this.target\n && this.target.value != '' \n && /[A-Z]+/.test(this.target.value) \n ) {\n this.target.value = this.value;\n }\n \n\n var rgx = /^(([^<>()[\\]\\\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n var isValid = rgx.test(this['value']) ? true : false;\n var errors = self[this['name']]['errors'] || {};\n\n if ( !errors['isRequired'] && this.value == '' ) {\n isValid = true;\n }\n\n if (!isValid) {\n errors['isEmail'] = replace(this['error'] || local.errorLabels['isEmail'], this)\n }\n // if error tagged by a previous vlaidation, remove it when isValid == true \n else if ( isValid && typeof(errors['isEmail']) != 'undefined' ) {\n delete errors['isEmail'];\n //delete errors['stack'];\n }\n\n this.valid = isValid;\n\n if ( errors.count() > 0 )\n this['errors'] = errors;\n\n return self[this['name']]\n }\n\n self[el]['isJsonWebToken'] = function() {\n\n\n this.value = local['data'][this.name] = (this.value) ? this.value.toLowerCase() : this.value;\n // Apply on current field upper -> lower\n if ( \n isGFFCtx\n && this.target\n && this.target.value != '' \n && /[A-Z]+/.test(this.target.value) \n ) {\n this.target.value = this.value;\n }\n\n var rgx = /^[A-Za-z0-9-_=]+\\.[A-Za-z0-9-_=]+\\.?[A-Za-z0-9-_.+/=]*$/;\n var isValid = rgx.test(this['value']) ? true : false;\n var errors = self[this['name']]['errors'] || {};\n\n if ( !errors['isRequired'] && this.value == '' ) {\n isValid = true;\n }\n\n if (!isValid) {\n errors['isJsonWebToken'] = replace(this['error'] || local.errorLabels['isJsonWebToken'], this)\n }\n // if error tagged by a previous vlaidation, remove it when isValid == true \n else if ( isValid && typeof(errors['isJsonWebToken']) != 'undefined' ) {\n delete errors['isJsonWebToken'];\n //delete errors['stack'];\n }\n\n this.valid = isValid;\n\n if ( errors.count() > 0 )\n this['errors'] = errors;\n\n return self[this['name']]\n }\n \n /**\n * Check if boolean and convert to `true/false` booloean if value is a string or a number\n * Will include `false` value if isRequired\n * */\n self[el]['isBoolean'] = function() {\n var val = null\n , errors = self[this['name']]['errors'] || {}\n ;\n\n if ( errors['isRequired'] && this.value == false) {\n isValid = true;\n delete errors['isRequired'];\n this['errors'] = errors;\n }\n\n switch(this.value) {\n case 'true':\n case true:\n case 1:\n val = this.value = local.data[this.name] = true;\n break;\n case 'false':\n case false:\n case 0:\n val = this.value = local.data[this.name] = false;\n break;\n }\n \n var isValid = (val !== null) ? true : false;\n\n if (!isValid) {\n errors['isBoolean'] = replace(this.error || local.errorLabels['isBoolean'], this)\n }\n // if error tagged by a previous vlaidation, remove it when isValid == true \n else if ( isValid && typeof(errors['isBoolean']) != 'undefined' ) {\n delete errors['isBoolean'];\n //delete errors['stack'];\n }\n\n this.valid = isValid;\n if ( errors.count() > 0 )\n this['errors'] = errors;\n\n return self[this.name]\n }\n\n /**\n * Check if value is an a Number.\n * - valid if a number is found\n * - cast into a number if a string is found\n * - if string is blank, no transformation will be done: valid if not required\n *\n * @param {number} minLength\n * @param {number} maxLength\n *\n * @return {object} result\n * */\n self[el]['isNumber'] = function(minLength, maxLength) {\n var val = this.value\n , len = 0\n , isValid = false\n , isMinLength = true\n , isMaxLength = true\n , errors = self[this['name']]['errors'] || {}\n ;\n \n // test if val is a number\n try {\n // if val is a string replaces comas by points\n if ( typeof(val) == 'string' && /\\,|\\./g.test(val) ) {\n val = local.data[this.name] = this.value = parseFloat( val.replace(/,/g, '.').replace(/\\s+/g, '') );\n } else if ( typeof(val) == 'string' && val != '') {\n val = local.data[this.name] = this.value = parseInt( val.replace(/\\s+/g, '') );\n }\n\n } catch (err) {\n errors['isNumber'] = replace(this.error || local.errorLabels['isNumber'], this);\n this.valid = false;\n if ( errors.count() > 0 )\n this['errors'] = errors;\n }\n\n if ( +val === +val ) {\n isValid = true;\n if ( !errors['isRequired'] && val != '' ) {\n len = val.toString().length;\n // if so also test max and min length if defined\n if (minLength && typeof(minLength) == 'number' && len < minLength) {\n isMinLength = false;\n this['size'] = minLength;\n }\n if (maxLength && typeof(maxLength) == 'number' && len > maxLength) {\n isMaxLength = false;\n this['size'] = maxLength;\n }\n }\n }\n\n // if val is invalid return error message\n if ( !isValid || !isMinLength || !isMaxLength ) {\n\n if ( !isValid )\n errors['isNumber'] = replace(this.error || local.errorLabels['isNumber'], this);\n if ( !isMinLength || !isMaxLength ) {\n if ( !isMinLength )\n errors['isNumberLength'] = replace(this.error || local.errorLabels['isNumberMinLength'], this);\n if ( !isMaxLength )\n errors['isNumberLength'] = replace(this.error || local.errorLabels['isNumberMaxLength'], this);\n if ( minLength === maxLength )\n errors['isNumberLength'] = replace(this.error || local.errorLabels['isNumberLength'], this);\n }\n\n isValid = false;\n }\n // if error tagged by a previous vlaidation, remove it when isValid == true \n if ( isValid && typeof(errors['isNumberLength']) != 'undefined') {\n delete errors['isNumberLength'];\n }\n\n this.valid = isValid;\n val = this.value = local.data[this.name] = ( val != '' ) ? Number(val) : val;\n if ( errors.count() > 0 )\n this['errors'] = errors;\n\n return self[this.name]\n }\n\n self[el]['toInteger'] = function() {\n var val = this.value\n , errors = self[this['name']]['errors'] || {}\n ;\n\n if (!val) {\n return self[this.name]\n } else {\n try {\n //val = this.value = local.data[this.name] = ~~(val.match(/[0-9]+/g).join(''));\n val = this.value = local.data[this.name] = Math.round(val);\n } catch (err) {\n\n errors['toInteger'] = replace(this.error || local.errorLabels['toInteger'], this);\n this.valid = false;\n if ( errors.count() > 0 )\n this['errors'] = errors;\n }\n\n }\n\n return self[this.name]\n }\n\n self[el]['isInteger'] = function(minLength, maxLength) {\n var val = this.value\n , isValid = false\n , isMinLength = true\n , isMaxLength = true\n , errors = self[this['name']]['errors'] || {}\n ;\n\n // test if val is a number\n if ( +val === +val && val % 1 === 0 ) {\n isValid = true;\n if ( !errors['isRequired'] && val != '' ) {\n // if so also test max and min length if defined\n if (minLength && typeof(minLength) == 'number' && val.length < minLength) {\n isMinLength = false;\n this['size'] = minLength;\n }\n if (maxLength && typeof(maxLength) == 'number' && val.length > maxLength) {\n isMaxLength = false;\n this['size'] = maxLength;\n }\n }\n }\n // if val is invalid return error message\n if ( !isValid || !isMinLength || !isMaxLength ) {\n\n if ( !isValid )\n errors['isInteger'] = replace(this.error || local.errorLabels['isInteger'], this);\n\n if ( !isMinLength || !isMaxLength ) {\n\n if ( !isMinLength ) {\n errors['isIntegerLength'] = replace(this.error || local.errorLabels['isIntegerMinLength'], this);\n isValid = false;\n }\n\n if ( !isMaxLength ) {\n errors['isIntegerLength'] = replace(this.error || local.errorLabels['isIntegerMaxLength'], this);\n isValid = false;\n }\n\n if ( minLength === maxLength ) {\n errors['isIntegerLength'] = replace(this.error || local.errorLabels['isIntegerLength'], this);\n isValid = false;\n }\n }\n }\n\n this.valid = isValid;\n val = this.value = local.data[this.name] = Number(val);\n\n if ( errors.count() > 0 )\n this['errors'] = errors;\n\n return self[this.name]\n }\n\n\n self[el]['toFloat'] = function(decimals) {\n if ( typeof(this.value) == 'string' ) {\n this.value = this.value.replace(/\\s+/g, '');\n if ( /\\,/.test(this.value) && !/\\./.test(this.value) ) {\n this.value = this.value.replace(/\\,/g,'.');\n //local.data[this.name] = this.value;\n // if (isGFFCtx) {\n // //this.target.setAttribute('value', this.value);\n // document.getElementById(this.target.id).value = this.value;\n // //triggerEvent(gina, this.target, 'change', self[this['name']]);\n // }\n \n } else {\n this.value = this.value.replace(/\\,/g,'');\n }\n }\n\n var val = local.data[this.name] = this.value\n , errors = self[this['name']]['errors'] || {}\n , isValid = true\n ;\n\n if (decimals) {\n this['decimals'] = parseInt(decimals)\n } else if ( typeof(this['decimals']) == 'undefined' ) {\n this['decimals'] = 2\n }\n\n if (!val) {\n return self[this.name]\n } else {\n if ( this['isNumber']().valid ) {\n try {\n\n if ( !Number.isFinite(val) ) {\n val = this.value = local.data[this.name] = new Number(parseFloat(val.match(/[0-9.,]+/g).join('').replace(/,/, '.')));// Number <> number\n }\n if (isGFFCtx)\n this.target.setAttribute('value', val);\n } catch(err) {\n isValid = false;\n errors['toFloat'] = replace(this.error || local.errorLabels['toFloat'], this);\n this.valid = false;\n if ( errors.count() > 0 )\n this['errors'] = errors;\n }\n } else {\n isValid = false;\n errors['toFloat'] = replace(this.error || local.errorLabels['toFloatNAN'], this)\n }\n }\n\n if (this['decimals'] && val && !errors['toFloat']) {\n this.value = local.data[this.name] = parseFloat(this.value.toFixed(this['decimals']));\n }\n\n this.valid = isValid;\n if ( errors.count() > 0 )\n this['errors'] = errors;\n\n return self[this.name]\n }\n\n /**\n * Check if value is float. No transformation is done here.\n * Can be used in combo preceded by *.toFloat(2) to transform data if needed:\n * 1 => 1.0\n * or\n * 3 500,5 => 3500.50\n *\n *\n * @param {number} [ decimals ]\n *\n * TODO - decimals transformation\n * */\n self[el]['isFloat'] = function(decimals) {\n\n if ( typeof(this.value) == 'string' ) {\n this.value = this.value.replace(/\\s+/g, '');\n }\n\n var val = local.data[this.name] = this.value\n , isValid = false\n , errors = self[this['name']]['errors'] || {}\n ;\n\n\n if ( typeof(val) == 'string' && /\\./.test(val) && Number.isFinite( Number(val) ) ) {\n isValid = true\n }\n\n // if string replaces comas by points\n if (typeof(val) == 'string' && /,/g.test(val)) {\n val = this.value = local.data[this.name] = Number(val.replace(/,/g, '.'))\n }\n\n // test if val is strictly a float\n if ( Number(val) === val && val % 1 !== 0 ) {\n this.value = local.data[this.name] = Number(val);\n isValid = true\n } else {\n isValid = false\n }\n\n if ( !errors['isRequired'] && this.value == '' ) {\n isValid = true\n }\n\n if (!isValid) {\n errors['isFloat'] = replace(this.error || local.errorLabels['isFloat'], this)\n }\n\n this.valid = isValid;\n if ( errors.count() > 0 )\n this['errors'] = errors;\n\n return self[this.name]\n }\n\n self[el]['isRequired'] = function(isApplicable) {\n\n if ( typeof(isApplicable) == 'boolean' && !isApplicable ) {\n\n this.valid = true;\n \n // is in excluded ?\n var excludedIndex = local.excluded.indexOf(this.name);\n if ( excludedIndex > -1 ) {\n local.excluded.splice(excludedIndex, 1);\n }\n\n return self[this.name]\n }\n\n // radio group case\n if ( \n isGFFCtx \n && this.target \n && this.target.tagName == 'INPUT' \n && typeof(this.target.type) != 'undefined' \n && this.target.type == 'radio' \n ) {\n var radios = document.getElementsByName(this.name);\n for (var i = 0, len = radios.length; i < len; ++i) {\n if (radios[i].checked) {\n if ( /true|false/.test(radios[i].value) ) {\n this.value = local.data[this.name] = ( /true/.test(radios[i].value) ) ? true : false\n } else {\n this.value = local.data[this.name] = radios[i].value;\n }\n\n this.valid = true;\n break;\n }\n }\n }\n\n\n var isValid = ( typeof(this.value) != 'undefined' && this.value != null && this.value != '' && !/^\\s+/.test(this.value) ) ? true : false;\n var errors = self[this['name']]['errors'] || {};\n\n\n if (!isValid) {\n errors['isRequired'] = replace(this.error || local.errorLabels['isRequired'], this)\n }\n // if error tagged by a previous vlaidation, remove it when isValid == true \n else if ( isValid ) {\n if (typeof(errors['isRequired']) != 'undefined' )\n delete errors['isRequired'];\n //delete errors['stack'];\n // if ( typeof(self[this.name]['errors']) != 'undefined' && typeof(self[this.name]['errors']['isRequired']) != 'undefined' )\n // delete self[this.name]['errors']['isRequired'];\n }\n\n this.valid = isValid;\n if (errors.count() > 0)\n this['errors'] = errors;\n\n return self[this.name]\n }\n /**\n *\n * isString() -> validate if value is string\n * isString(10) -> validate if value is at least 10 chars length\n * isString(0, 45) -> no minimum length, but validate if value is maximum 45 chars length\n * NB.:\n * In your JSON rule ;\n * {\n * \"password\": {\n * \"isRequired\": true,\n * \n * \"isString\": true // Means that we just want a string and we don't care of its length\n * // OR\n * \"isString\": 7 // Means at least 7 chars length\n * // OR\n * \"isString\": [7, 40] // Means at least 7 chars length and maximum 40 chars length\n * // OR\n * \"isString\": [7] // Means is strickly equal to 7 chars length, same as [7,7]\n * }\n * }\n * @param {number|undefined} [ minLength ]\n * @param {number} [ maxLength ]\n * */\n self[el]['isString'] = function(minLength, maxLength) {\n\n var val = local.data[this.name] = this.value\n , isValid = false\n , isMinLength = true\n , isMaxLength = true\n , errors = self[this['name']]['errors'] || {}\n ;\n\n\n // test if val is a string\n if ( typeof(val) == 'string' ) {\n //isValid = true;\n\n if ( !errors['isRequired'] && val != '' ) {\n isValid = true;\n // if so also test max and min length if defined\n if (minLength && typeof(minLength) == 'number' && val.length < minLength) {\n isMinLength = false;\n this['size'] = minLength;\n }\n if (maxLength && typeof(maxLength) == 'number' && val.length > maxLength) {\n isMaxLength = false;\n this['size'] = maxLength;\n }\n }\n\n }\n\n // if val is invalid return error message\n if (!isValid || !isMinLength || !isMaxLength ) {\n\n if (!isValid && errors['isRequired'] && val == '') {\n isValid = false;\n errors['isString'] = replace(this['error'] || local.errorLabels['isString'], this);\n } else if (!isValid && !errors['isRequired']) {\n isValid = true;\n }\n\n if ( !isMinLength || !isMaxLength) {\n isValid = false;\n\n if ( !isMinLength )\n errors['isStringLength'] = replace(this['error'] || local.errorLabels['isStringMinLength'], this);\n if ( !isMaxLength )\n errors['isStringLength'] = replace(this['error'] || local.errorLabels['isStringMaxLength'], this);\n if (minLength === maxLength)\n errors['isStringLength'] = replace(this['error'] || local.errorLabels['isStringLength'], this);\n }\n\n }\n\n this.valid = isValid;\n if ( errors.count() > 0 ) {\n this['errors'] = errors;\n }\n\n return self[this.name]\n }\n\n /**\n * Check if date\n *\n * @param {string|boolean} [mask] - by default \"yyyy-mm-dd\"\n *\n * @return {date} date - extended by gina::utils::dateFormat; an adaptation of Steven Levithan's code\n * */\n self[el]['isDate'] = function(mask) { \n var val = this.value\n , isValid = false\n , errors = self[this['name']]['errors'] || {}\n , m = null\n , date = null\n ;\n // Default validation on livecheck & invalid init value\n if (!val || val == '' || /NaN|Invalid Date/i.test(val) ) { \n if ( /NaN|Invalid Date/i.test(val) ) {\n console.warn('[FormValidator::isDate] Provided value for field `'+ this.name +'` is not allowed: `'+ val +'`');\n errors['isDate'] = replace(this.error || local.errorLabels['isDate'], this);\n \n }\n this.valid = isValid;\n if ( errors.count() > 0 )\n this['errors'] = errors; \n \n return self[this.name];\n }\n \n if ( \n typeof(mask) == 'undefined'\n ||\n typeof(mask) != 'undefined' && /true/i.test(mask)\n ) {\n mask = \"yyyy-mm-dd\"; // by default\n }\n \n if (val instanceof Date) {\n date = val.format(mask);\n } else {\n \n try {\n m = mask.match(/[^\\/\\- ]+/g);\n } catch (err) {\n throw new Error('[FormValidator::isDate] Provided mask not allowed: `'+ mask +'`');\n }\n \n try {\n val = val.match(/[^\\/\\- ]+/g);\n var dic = {}, d, len;\n for (d=0, len=m.length; d<len; ++d) {\n dic[m[d]] = val[d]\n }\n var formatedDate = mask;\n for (var v in dic) {\n formatedDate = formatedDate.replace(new RegExp(v, \"g\"), dic[v])\n }\n } catch (err) {\n throw new Error('[FormValidator::isDate] Provided value not allowed: `'+ val +'`' + err);\n }\n \n\n date = this.value = local.data[this.name] = new Date(formatedDate);\n \n if ( /Invalid Date/i.test(date) || date instanceof Date === false ) {\n if ( !errors['isRequired'] && this.value == '' ) {\n isValid = true\n } else {\n errors['isDate'] = replace(this.error || local.errorLabels['isDate'], this);\n }\n\n this.valid = isValid;\n if ( errors.count() > 0 )\n this['errors'] = errors;\n\n return self[this.name]\n }\n isValid = true;\n }\n\n this.valid = isValid;\n\n return date\n }\n\n /**\n * Formating date using DateFormatHelper\n * Check out documentation in the helper source: `utils/helpers/dateFormat.js`\n * e.g.:\n * d.start\n * .isDate('dd/mm/yyyy')\n * .format('isoDateTime');\n *\n *\n * */\n self[el]['format'] = function(mask, utc) {\n var val = this.value;\n if (!val) return self[this.name];\n\n return val.format(mask, utc)\n };\n\n /**\n * Set flash\n *\n * @param {str} flash\n * */\n self[el]['setFlash'] = function(regex, flash) {\n if ( typeof(flash) != 'undefined' && flash != '') {\n this.error = flash\n }\n return self[this.name]\n }\n\n /**\n * Set label\n *\n * @param {str} label\n * */\n self[el]['setLabel'] = function(label) {\n if ( typeof(label) != 'undefined' && label != '') {\n this.label = label\n }\n return self[this.name]\n }\n \n /**\n * Trim when string starts or ends with white space(s)\n *\n * @param {str} trimmed off string\n * */\n self[el]['trim'] = function(isApplicable) {\n if ( typeof(isApplicable) == 'boolean' && isApplicable ) {\n //if ( typeof(this.value) == 'string' ) {\n this.value = this.value.replace(/^\\s+|\\s+$/, '');\n local.data[this.name] = local.data[this.name] = this.value;\n //}\n return self[this.name]\n }\n }\n\n /**\n * Exclude when converting back to datas\n *\n * @return {object} data\n * */\n self[el]['exclude'] = function(isApplicable) {\n\n if ( typeof(isApplicable) == 'boolean' && !isApplicable ) {\n \n if ( /^true|false$/i.test(this.value)) {\n this.value = (/^true$/i.test(this.value)) ? true : false;\n local.data[this.name] = this.value;\n } \n\n return self[this.name]\n }\n this.isExcluded = false;\n // list field to be purged\n if ( local.excluded.indexOf(this.name) < 0) {\n local.excluded.push(this.name);\n this.isExcluded = true;\n }\n \n \n // remove existing errors\n return self[this.name];\n }\n /**\n * Validation through API call\n * Try to put this rule at the end to prevent sending\n * a request to the remote host if previous rules failed\n */\n self[el]['query'] = query;\n \n // Merging user validators\n // To debug, open inspector and look into `Extra Scripts` \n if ( hasUserValidators() ) {\n var userValidator = null, filename = null, virtualFileForDebug = null;\n try { \n for (let v in gina.forms.validators) {\n \n // Blocking default validators overrive\n // if ( typeof(self[el][v]) != 'undefined' ) {\n // continue;\n // }\n filename = '/validators/'+ v + '/main.js';\n // setting default local error\n local.errorLabels[v] = 'Condition not satisfied';\n // converting Buffer to string\n if ( isGFFCtx ) {\n //userValidatorError = String.fromCharCode.apply(null, new Uint16Array(gina.forms.validators[v].data));\n userValidator = bufferToString(gina.forms.validators[v].data);\n //userValidator += '\\n//#sourceURL='+ v +'.js';\n } else {\n userValidator = gina.forms.validators[v].toString();\n } \n self[el][v] = eval('(' + userValidator + ')\\n//# sourceURL='+ v +'.js');\n }\n } catch (userValidatorError) {\n throw new Error('[UserFormValidator] Could not evaluate: `'+ filename +'`\\n'+userValidatorError.stack);\n }\n }\n } // EO addField(el, value) \n \n \n for (let el in self) { \n // Adding fields & validators to context\n //addField(el); \n addField(el, self[el]);\n }\n \n self['addField'] = function(el, value) {\n if ( typeof(self[el]) != 'undefined' ) {\n return\n }\n addField(el, value);\n };\n \n // self['getExcludedFields'] = function() {\n // return local.excluded;\n // };\n\n /**\n * Check if errors found during validation\n *\n * @return {boolean}\n * */\n self['isValid'] = function() {\n return (self['getErrors']().count() > 0) ? false : true;\n }\n self['setErrors'] = function(errors) {\n if (!errors) {\n return {}\n }\n for (var field in self) {\n if ( typeof(self[field]) != 'object' ) {\n continue\n }\n // if ( typeof(self[field]['errors']) == 'undefined' || self[field]['errors'].count() == 0 ) {\n // delete errors[field];\n // continue;\n // }\n // if ( typeof(errors[field]) == 'undefined' ) {\n // continue;\n // }\n for (var r in self[field]) {\n // no error for the current field rule\n if ( \n typeof(errors[field]) != 'object'\n ||\n typeof(errors[field][r]) == 'undefined'\n ) {\n continue;\n }\n \n \n if ( \n typeof(self[field].valid) != 'undefined' \n && /^true$/i.test(self[field].valid) \n ) {\n delete errors[field][r];\n continue;\n }\n \n \n if ( typeof( self[field]['errors']) == 'undefined' ) {\n self[field]['errors'] = {}\n }\n \n self[field]['errors'][r] = errors[field][r]; \n }\n \n // if field does not have errors, remove errors[field]\n if ( \n typeof(self[field]['errors']) == 'undefined'\n && typeof(errors[field]) != 'undefined'\n ||\n typeof(self[field]['errors']) != 'undefined'\n && self[field]['errors'].count() == 0\n && typeof(errors[field]) != 'undefined'\n ) {\n delete errors[field];\n continue;\n }\n }\n return errors;\n }\n /**\n * getErrors\n * NB.: This portion is shared between the front & the back\n * \n * @param {string} [fieldName]\n * \n * @returns errors\n */\n self['getErrors'] = function(fieldName) {\n var errors = {};\n \n if ( typeof(fieldName) != 'undefined' ) {\n if ( typeof(self[fieldName]) != 'undefined' && self[fieldName] && typeof(self[fieldName]['errors']) != 'undefined' && self[fieldName]['errors'].count() > 0 ) {\n errors[fieldName] = self[fieldName]['errors'];\n } \n return errors\n }\n \n for (var field in self) {\n if ( \n typeof(self[field]) != 'object'\n ) {\n continue;\n }\n \n if ( typeof(self[field]['errors']) != 'undefined' ) {\n if ( self[field]['errors'].count() > 0)\n errors[field] = self[field]['errors'];\n }\n }\n \n return errors\n }\n\n self['toData'] = function() {\n\n // cleaning data\n if (local.excluded.length > 0) {\n for (var i = 0, len = local.excluded.length; i < len; ++i) {\n if ( typeof(local.data[ local.excluded[i] ]) != 'undefined' ) {\n delete local.data[ local.excluded[i] ]\n }\n }\n }\n // local.data = JSON.parse(JSON.stringify(local.data).replace(/\\\"(true|false)\\\"/gi, '$1'))\n return local.data\n }\n\n var replace = function(target, fieldObj) {\n var keys = target.match(/%[a-z]+/gi);\n if (keys) {\n for (var k = 0, len = keys.length; k < len; ++k) {\n target = target.replace(new RegExp(keys[k], 'g'), fieldObj[local.keys[keys[k]]])\n }\n }\n\n return target\n }\n\n self['setErrorLabels'] = function (errorLabels) {\n if ( typeof(errorLabels) != 'undefined') {\n local.errorLabels = merge(errorLabels, local.errorLabels)\n }\n }\n\n return self\n};\n\nif ( ( typeof(module) !== 'undefined' ) && module.exports ) {\n // Publish as node.js module\n module.exports = FormValidatorUtil\n} else if ( typeof(define) === 'function' && define.amd) {\n // Publish as AMD module\n define('utils/form-validator',[],function() { return FormValidatorUtil })\n};\n",
41
- "/*\n * This file is part of the gina package.\n * Copyright (c) 2009-2022 Rhinostone <contact@gina.io>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * Routing\n *\n * @package Gina.Lib\n * @namespace Gina.Lib.Routing\n * @author Rhinostone <contact@gina.io>\n * */\n\nfunction Routing() {\n\n var isGFFCtx = ((typeof (module) !== 'undefined') && module.exports) ? false :  true;\n var self = {\n allowedMethods: ['get', 'post', 'put', 'delete'],\n reservedParams: ['controle', 'file','title', 'namespace', 'path'],\n notFound: {}\n }; \n \n self.allowedMethodsString = self.allowedMethods.join(',');\n \n // loading utils & plugins\n var plugins = null, inherits = null, merge = null, Validator = null, fs = null, promisify = null;\n if (!isGFFCtx) {\n fs = require('fs');\n promisify = require('util').promisify;\n inherits = require('../../inherits');\n merge = require('../../merge');\n plugins = require(__dirname+'/../../../core/plugins') || getContext('gina').plugins;\n Validator = plugins.Validator;\n \n } \n // BO - In case of partial rendering whithout handler defined for the partial\n else {\n if ( !merge || typeof(merge) != 'function' ) {\n var merge = require('utils/merge');\n }\n if ( !Validator || typeof(Validator) != 'function' ) {\n var Validator = require('utils/form-validator');\n }\n } \n // EO - In case of partial rendering whithout handler defined for the partial\n \n /**\n * Get url props\n * Used to retrieve additional properties for routes with redirect flag for example\n * \n * @param {string} [bundle]\n * @param {string} [env] \n * \n * @return {object} urlProps - { .host, .hostname, .webroot }\n */\n self.getUrlProps = function(bundle, env) {\n var config = null, urlProps = {}, _route = null;\n if (isGFFCtx) {\n // TODO - add support to get from env\n config = window.gina.config;\n // by default\n urlProps.hostname = config.hostname;\n if ( typeof(bundle) != 'undefined' ) {\n // get from webroot\n _route = routing.getRoute('webroot@'+ bundle);\n urlProps.hostname = _route.hostname;\n urlProps.host = _route.host;\n urlProps.webroot = _route.webroot;\n } \n } else {\n config = getContext('gina').config;\n if ( typeof(getContext('argvFilename')) != 'undefined' ) {\n config.getRouting = getContext('gina').Config.instance.getRouting\n }\n if ( typeof(bundle) == 'undefined' ) {\n bundle = config.bundle;\n }\n if ( typeof(env) == 'undefined' ) {\n env = config.env;\n }\n \n urlProps.hostname = config.envConf[bundle][env].hostname;\n urlProps.host = config.envConf[bundle][env].host;\n urlProps.webroot = config.envConf[bundle][env].server.webroot;\n }\n \n return urlProps;\n }\n \n /**\n * Load bundle routing configuration\n * \n * @param {object} options\n * {\n * isStadalone: false,\n * bundle: 'default', // bundle's name\n * wroot: '/', // by default\n * \n * }\n * \n */\n // self.loadBundleRoutingConfiguration = function(options, filename) {\n \n // }\n \n /**\n * Get routing\n * \n * @param {string} [bundle]\n */\n // self.getRouting = function(bundle) {\n \n // }\n \n /**\n * Get reversed routing\n * \n * @param {string} [bundle]\n */\n // self.getReverseRouting = function(bundle) {\n \n // }\n\n /**\n * Compare urls\n *\n * @param {object} params - Route params containing the given url to be compared with\n * @param {string|array} url - routing.json url\n * @param {object} [request]\n * @param {object} [response] - only used for query validation\n * @param {object} [next] - only used for query validation\n *\n * @return {object|false} foundRoute\n * */\n self.compareUrls = async function(params, url, request, response, next) {\n \n if ( typeof(request) == 'undefined' ) {\n request = { routing: {} };\n }\n // Sample debug break for specific rule\n // if ( params.rule == 'my-specific-rule@bundle' ) {\n // console.debug('passed '+ params.rule);\n // }\n if ( /\\,/.test(url) ) {\n var i = 0\n , urls = url.split(/\\,/g)\n , len = urls.length\n , foundRoute = {\n past: false,\n request: request\n };\n\n\n while (i < len && !foundRoute.past) {\n foundRoute = await parseRouting(params, urls[i], request, response, next);\n ++i;\n }\n\n return foundRoute;\n } else {\n return await parseRouting(params, url, request, response, next);\n }\n };\n\n /**\n * Check if rule has params\n *\n * @param {string} pathname\n * @return {boolean} found\n *\n * @private\n * */\n var hasParams = function(pathname) {\n return (/:/.test(pathname)) ? true : false;\n };\n\n /**\n * Parse routing for mathcing url\n *\n * @param {object} params - `params` is the same `request.routing` that can be retried in controller with: req.routing\n * @param {string} url\n * @param {object} request\n * @param {object} [response] - Only used for query validation\n * @param {object} [next] - Only used for query validation\n *\n * @return {object} foundRoute\n *\n * */\n var parseRouting = async function(params, url, request, response, next) {\n \n // Sample debug break for specific rule\n // if ( params.rule == 'my-specific-rule@bundle' ) {\n // console.debug('passed '+ params.rule);\n // }\n \n var uRe = params.url.split(/\\//)\n , uRo = url.split(/\\//)\n , uReCount = 0\n , uRoCount = 0\n , maxLen = uRo.length\n , score = 0\n , foundRoute = {}\n , i = 0\n , method = request.method.toLowerCase()\n ;\n \n // TODO - remove comments\n // when requirement is not listed but still validated\n // if ( \n // typeof(params.requirements) != 'undefined' \n // && method == params.method.toLowerCase()\n // //&& /validator\\:\\:/.test(JSON.stringify(params.requirements))\n // ) {\n \n // var requiremements = Object.getOwnPropertyNames(params.requirements);\n // var r = 0;\n // // In order to filter variables\n // var uRoVars = uRo.join(',').match(/\\:[-_a-z0-9]+/g);\n // // var uRoVarCount = (uRoVars) ? uRoVars.length : 0;\n // while ( r < requiremements.length ) {\n \n // // if not listed, but still needing validation\n // if ( \n // typeof(params.param[ requiremements[r] ]) == 'undefined' \n // && /^validator\\:\\:/i.test(params.requirements[ requiremements[r] ])\n // && typeof(request[method][ requiremements[r] ])\n // ) {\n // if (uRo.length != uRe.length) {\n // // r++; \n // // continue;\n // break;\n // }\n // // updating uRoVars\n // uRoVars = uRo.join(',').match(/\\:[-_a-z0-9]+/g);\n // /**\n // * \"requirements\" : {\n // * \"email\": \"validator::{ isEmail: true, isString: [7] }\"\n // * }\n // * \n // * e.g.: result = new Validator('routing', _data, null, {email: {isEmail: true, subject: \\\"Anything\\\"}} ).isEmail().valid;\n // */ \n // let regex = params.requirements[ requiremements[r] ];\n // let _data = {}, _ruleObj = {}, _rule = {};\n \n // try {\n // _ruleObj = JSON.parse(\n // regex.split(/::/).splice(1)[0]\n // .replace(/([^\\:\\\"\\s+](\\w+))\\:/g, '\"$1\":') // { query: { validIf: true }} => { \"query\": { \"validIf\": true }}\n // .replace(/([^\\:\\\"\\s+](\\w+))\\s+\\:/g, '\"$1\":') // note the space between `validIf` & `:` { query: { validIf : true }} => { \"query\": { \"validIf\": true }}\n // ); \n // } catch (err) {\n // throw err;\n // }\n \n // let key = requiremements[r];\n // // validator.query case\n // if (typeof(_ruleObj.query) != 'undefined' && typeof(_ruleObj.query.data) != 'undefined') {\n // _data = _ruleObj.query.data;\n // // filter _data vs uRoVars by removing from data those not present in uRoVars\n // for (let k in _data) {\n // if ( uRoVars.indexOf(_data[k]) < 0 ) {\n // delete _data[k]\n // }\n // }\n // for (let p = 0, pLen = uRo.length; p < pLen; p++) {\n // // :variable only\n // if (!/^\\:/.test(uRo[p])) continue;\n \n // let pName = uRo[p].replace(/^\\:/, '');\n // if ( pName != '' && typeof(uRe[p]) != 'undefined' ) {\n // _data[ pName ] = uRe[p];\n // // Updating params\n // if ( typeof(request.params[pName]) == 'undefined' ) {\n // // Set in case it is not found\n // request.params[pName] = uRe[p];\n // }\n // }\n // } \n // }\n // // normal case\n // _data = merge(_data, request[method]);\n \n // if ( typeof(_data[key]) == 'undefined' ) {\n // // init default value for unlisted variable/param\n // _data[key] = null;\n // }\n \n // _rule[key] = _ruleObj; \n // _validator = new Validator('routing', _data, null, _rule );\n \n // if (_ruleObj.count() == 0 ) {\n // console.error('Route validation failed '+ params.rule);\n // return false;\n // }\n \n // for (let rule in _ruleObj) {\n // let _result = null;\n // if (Array.isArray(_ruleObj[rule])) { // has args\n // _result = await _validator[key][rule].apply(_validator[key], _ruleObj[rule]);\n // } else {\n // _result = await _validator[key][rule](_ruleObj[rule], request, response, next);\n // }\n // //let condition = _ruleObj[rule].validIf.replace(new RegExp('\\\\$isValid'), _result.isValid);\n // // if ( eval(condition)) {\n // if ( !_result.isValid ) {\n // --score;\n // }\n // }\n // }\n // r++\n // }\n // }\n \n // attaching routing description for this request\n var paramMethod = params.method.toLowerCase();\n \n var hasAlreadyBeenScored = false;\n if ( \n typeof(params.requirements) != 'undefined'\n && /get|delete/i.test(method)\n && typeof(request[method]) != 'undefined'\n ||\n // GET request is in fact in this case a DELETE request\n typeof(params.requirements) != 'undefined'\n && /get/i.test(method)\n && /delete/i.test(paramMethod)\n ) { \n if ( /get/i.test(method) && /delete/i.test(paramMethod) ) {\n method = paramMethod;\n }\n // `delete` methods don't have a body\n // So, request.delete is {} by default\n if ( /^(delete)$/i.test(method) && uRe.length === uRo.length ) { \n // just in case\n if ( typeof(request[method]) == 'undefined' ) {\n request[method] = {};\n }\n for (let p = 0, pLen = uRo.length; p < pLen; p++) {\n if (uRe[p] === uRo[p]) { \n ++score; \n continue;\n }\n let _key = uRo[p].substr(1);\n if ( typeof(params.requirements[_key]) == 'undefined' ) {\n continue;\n }\n let condition = params.requirements[_key];\n if ( /^\\//.test(condition) ) {\n condition = condition.substr(1, condition.lastIndexOf('/')-1);\n } else if ( /^validator\\:\\:/.test(condition) && await fitsWithRequirements(uRo[p], uRe[p], params, request, response, next) ) {\n ++score;\n continue;\n }\n if (\n /^:/.test(uRo[p]) \n && typeof(condition) != 'undefined'\n && new RegExp(condition).test(uRe[p])\n ) {\n ++score; \n request[method][uRo[p].substr(1)] = uRe[p]; \n }\n }\n hasAlreadyBeenScored = true; \n } \n \n // Sample debug break for specific rule\n // if ( params.rule == 'my-specific-rule@bundle' ) {\n // console.debug('passed '+ params.rule);\n // }\n for (let p in request[method]) {\n if ( typeof(params.requirements[p]) != 'undefined' && uRo.indexOf(':' + p) < 0 ) {\n uRo[uRoCount] = ':' + p; \n ++uRoCount;\n \n uRe[uReCount] = request[method][p];\n ++uReCount;\n if (!hasAlreadyBeenScored && uRe.length === uRo.length)\n ++maxLen; \n }\n }\n }\n \n \n // Sample debug break for specific rule\n // if ( params.rule == 'my-specific-rule@bundle' ) {\n // console.debug('passed '+ params.rule);\n // }\n \n if (!hasAlreadyBeenScored && uRe.length === uRo.length) {\n \n for (; i < maxLen; ++i) {\n \n if (uRe[i] === uRo[i]) {\n ++score;\n }\n else if (score == i && hasParams(uRo[i]) && await fitsWithRequirements(uRo[i], uRe[i], params, request, response, next)) {\n ++score;\n }\n }\n }\n \n // This test is done to catch `validator::` rules under requirements\n if ( \n typeof(params.requirements) != 'undefined' \n && method == params.method.toLowerCase()\n && !hasAlreadyBeenScored\n && score >= maxLen\n ) {\n \n var requiremements = Object.getOwnPropertyNames(params.requirements);\n var r = 0;\n // In order to filter variables\n var uRoVars = uRo.join(',').match(/\\:[-_a-z0-9]+/g);\n // var uRoVarCount = (uRoVars) ? uRoVars.length : 0;\n while ( r < requiremements.length ) {\n // requirement name as `key`\n let key = requiremements[r];\n // if not listed, but still needing validation\n if ( \n typeof(params.param[ key ]) == 'undefined' \n && /^validator\\:\\:/i.test(params.requirements[ key ])\n ) {\n if (uRo.length != uRe.length) {\n // r++; \n // continue;\n break;\n }\n // updating uRoVars\n uRoVars = uRo.join(',').match(/\\:[-_a-z0-9]+/g);\n /**\n * \"requirements\" : {\n * \"email\": \"validator::{ isEmail: true, isString: [7] }\"\n * }\n * \n * e.g.: result = new Validator('routing', _data, null, {email: {isEmail: true, subject: \\\"Anything\\\"}} ).isEmail().valid;\n */ \n let regex = params.requirements[ key ];\n let _data = {}, _ruleObj = {}, _rule = {};\n \n try {\n _ruleObj = JSON.parse(\n regex.split(/::/).splice(1)[0]\n .replace(/([^\\:\\\"\\s+](\\w+))\\:/g, '\"$1\":') // { query: { validIf: true }} => { \"query\": { \"validIf\": true }}\n .replace(/([^\\:\\\"\\s+](\\w+))\\s+\\:/g, '\"$1\":') // note the space between `validIf` & `:` { query: { validIf : true }} => { \"query\": { \"validIf\": true }}\n ); \n } catch (err) {\n throw err;\n }\n \n // validator.query case\n if (typeof(_ruleObj.query) != 'undefined' && typeof(_ruleObj.query.data) != 'undefined') {\n _data = _ruleObj.query.data;\n // filter _data vs uRoVars by removing from data those not present in uRoVars\n for (let k in _data) {\n if ( uRoVars.indexOf(_data[k]) < 0 ) {\n delete _data[k]\n }\n }\n for (let p = 0, pLen = uRo.length; p < pLen; p++) {\n // :variable only\n if (!/^\\:/.test(uRo[p])) continue;\n \n let pName = uRo[p].replace(/^\\:/, '');\n if ( pName != '' && typeof(uRe[p]) != 'undefined' ) {\n _data[ pName ] = uRe[p];\n // Updating params\n if ( typeof(request.params[pName]) == 'undefined' ) {\n // Set in case if not found\n request.params[pName] = uRe[p];\n }\n }\n } \n }\n \n // If validator.query has data, _data should inherit from request data\n _data = merge(_data, JSON.clone(request[method]) || {} );\n // This test is to initialize query.data[key] to null by default\n if ( typeof(_data[key]) == 'undefined' ) {\n // init default value for unlisted variable/param\n _data[key] = null;\n }\n \n _rule[key] = _ruleObj; \n if (!isGFFCtx) {\n _validator = new Validator('routing', _data, null, _rule );\n } else {\n _validator = new Validator(_data);\n }\n \n if (_ruleObj.count() == 0 ) {\n console.error('Route validation failed '+ params.rule);\n --score;\n r++;\n continue;\n } \n // for each validation rule\n for (let rule in _ruleObj) {\n // updating query.data\n if (typeof(_ruleObj[rule].data) != 'undefined') {\n _ruleObj[rule].data = _data;\n }\n let _result = null;\n if (Array.isArray(_ruleObj[rule])) { // has args\n _result = await _validator[key][rule].apply(_validator[key], _ruleObj[rule]);\n } else {\n _result = await _validator[key][rule](_ruleObj[rule], request, response, next);\n } \n \n //let condition = _ruleObj[rule].validIf.replace(new RegExp('\\\\$isValid'), _result.isValid);\n // if ( eval(condition)) {\n if ( !_result.isValid ) {\n --score;\n if ( typeof(_result.error) != 'undefined' ) {\n throw _result.error;\n }\n }\n }\n }\n r++\n }\n }\n\n foundRoute.past = (score === maxLen) ? true : false;\n \n if (foundRoute.past) {\n // attaching routing description for this request\n //request.routing = params; // can be retried in controller with: req.routing\n // && replacing placeholders\n request.routing = checkRouteParams(params, request[method]);\n foundRoute.request = request;\n }\n \n\n return foundRoute;\n };\n\n /**\n * Fits with requiremements\n * This is for server side use only\n * http://en.wikipedia.org/wiki/Regular_expression\n *\n * @param {string} urlVar\n * @param {string} urlVal\n * @param {object} params\n *\n * @return {boolean} true|false - `true` if it fits\n *\n * @private\n * */\n var fitsWithRequirements = async function(urlVar, urlVal, params, request, response, next) {\n // Sample debug break for specific rule\n // if ( params.rule == 'my-specific-rule@bundle' ) {\n // console.debug('passed '+ params.rule);\n // }\n //var isValid = new Validator('routing', { email: \"contact@gina.io\"}, null, {email: {isEmail: true}} ).isEmail().valid;\n var matched = -1\n , _param = urlVar.match(/\\:\\w+/g)\n , regex = new RegExp(urlVar, 'g')\n , re = null\n , flags = null\n , key = null\n , tested = false\n \n , _validator = null\n , _data = null\n , _ruleObj = null\n , _rule = null\n , rule = null\n , str = null\n // request method\n , requestMethod = request.method.toLowerCase()\n ;\n \n if (!_param.length) return false;\n\n // if custom path, path rewrite\n if (params.param.path && regex.test(params.param.path)) {\n params.param.path = params.param.path.replace(regex, urlVal);\n }\n \n // if custom namespace, namespace rewrite\n if (params.param.namespace && regex.test(params.param.namespace)) { \n params.param.namespace = params.param.namespace.replace(regex, urlVal); \n }\n \n // if custom file, file rewrite\n // if (params.param.file && regex.test(params.param.file)) { \n // params.param.file = params.param.file.replace(regex, urlVal); \n // }\n // file is handle like url replacement (path is like pathname)\n if (typeof (params.param.file) != 'undefined' && /:/.test(params.param.file)) {\n var _regex = new RegExp('(:'+urlVar+'/|:'+urlVar+'$)', 'g'); \n replacement.variable = urlVal; \n params.param.file = params.param.file.replace( _regex, replacement );\n }\n\n // if custom title, title rewrite\n if (params.param.title && regex.test(params.param.title)) { \n params.param.title = params.param.title.replace(regex, urlVal);\n }\n\n if (_param.length == 1) { // fast one\n \n re = new RegExp( _param[0]);\n matched = (_param.indexOf(urlVar) > -1) ? _param.indexOf(urlVar) : false;\n \n if (matched === false ) {\n // In order to support rules defined like :\n // { params.url } => `/section/:name/page:number`\n // { request.url } => `/section/plante/page4`\n //\n // with keys = [ \":name\", \":number\" ]\n \n if ( urlVar.match(re) ) {\n matched = 0;\n }\n }\n \n\n if (matched === false) return matched;\n // filter on method\n if (params.method.toLowerCase() !== requestMethod) return false;\n \n if ( typeof(request[requestMethod]) == 'undefined' ) {\n request[requestMethod] = {}\n }\n\n key = _param[matched].substr(1);\n // escaping `\\` characters\n // TODO - remove comment : all regex requirement must start with `/`\n //regex = ( /\\\\/.test(params.requirements[key]) ) ? params.requirements[key].replace(/\\\\/, '') : params.requirements[key];\n regex = params.requirements[key];\n if (/^\\//.test(regex)) {\n re = regex.match(/\\/(.*)\\//).pop();\n flags = regex.replace('/' + re + '/', ''); \n\n tested = new RegExp(re, flags).test(urlVal)\n } else if ( /^validator\\:\\:/.test(regex) && urlVal) {\n /**\n * \"requirements\" : {\n * \"id\" : \"/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\",\n * \"email\": \"validator::{ isEmail: true, isString: [7] }\"\n * }\n * \n * e.g.: tested = new Validator('routing', _data, null, {email: {isEmail: true, subject: \\\"Anything\\\"}} ).isEmail().valid;\n */ \n _data = {}; _ruleObj = {}; _rule = {}; str = ''; \n urlVar.replace( new RegExp('[^'+ key +']','g'), function(){ str += arguments[0] }); \n _data[key] = urlVal.replace( new RegExp(str, 'g'), '');\n try {\n //_ruleObj = JSON.parse(regex.split(/::/).splice(1)[0].replace(/([^\\W+ true false])+(\\w+)/g, '\"$&\"'));\n _ruleObj = JSON.parse(\n regex.split(/::/).splice(1)[0]\n .replace(/([^\\:\\\"\\s+](\\w+))\\:/g, '\"$1\":') // { query: { validIf: true }} => { \"query\": { \"validIf\": true }}\n .replace(/([^\\:\\\"\\s+](\\w+))\\s+\\:/g, '\"$1\":') // note the space between `validIf` & `:` { query: { validIf : true }} => { \"query\": { \"validIf\": true }}\n ); \n } catch (err) {\n throw err;\n }\n //_ruleObj = JSON.parse(regex.split(/::/).splice(1)[0].replace(/([^\\W+ true false])+(\\w+)/g, '\"$&\"')); \n if (typeof(_ruleObj.query) != 'undefined' && typeof(_ruleObj.query.data) != 'undefined') {\n // since we only have one param\n // :var1 == :var1\n if ( urlVar == _ruleObj.query.data[ Object.keys(_ruleObj.query.data)[0] ] ) {\n _ruleObj.query.data[ Object.keys(_ruleObj.query.data)[0] ] = _data[key];\n // Set in case it is not found\n request.params[key] = _data[key];\n }\n }\n _rule[key] = _ruleObj; \n _validator = new Validator('routing', _data, null, _rule );\n if (_ruleObj.count() == 0 ) {\n console.error('Route validation failed '+ params.rule);\n return false;\n }\n for (let rule in _ruleObj) {\n if (Array.isArray(_ruleObj[rule])) { // has args\n await _validator[key][rule].apply(_validator[key], _ruleObj[rule]);\n } else {\n await _validator[key][rule](_ruleObj[rule], request, response, next);\n } \n }\n tested = _validator.isValid();\n } else {\n tested = new RegExp(params.requirements[key]).test(urlVal);\n }\n\n if (\n typeof(params.param[key]) != 'undefined' &&\n typeof(params.requirements) != 'undefined' &&\n typeof(params.requirements[key]) != 'undefined' &&\n typeof(request.params) != 'undefined' &&\n tested\n ) { \n request.params[key] = urlVal;\n if ( typeof(request[requestMethod][key]) == 'undefined' ) {\n request[requestMethod][key] = urlVal;\n }\n return true;\n }\n\n } else { // slow one\n\n // In order to support rules defined like :\n // { params.url } => `/section/:name/page:number`\n // { request.url } => `/section/plante/page4`\n //\n // with keys = [ \":name\", \":number\" ]\n\n var keys = _param\n , tplUrl = params.url\n , url = request.url\n , values = {}\n , strVal = ''\n , started = false\n , i = 0\n ;\n\n for (var c = 0, posLen = url.length; c < posLen; ++c) {\n if (url.charAt(c) == tplUrl.charAt(i) && !started) {\n ++i\n continue\n } else if (strVal == '') { // start\n\n started = true;\n strVal += url.charAt(c);\n } else if (c > (tplUrl.indexOf(keys[0]) + keys[0].length)) {\n\n regex = params.requirements[keys[0]];\n urlVal = strVal.substr(0, strVal.length);\n\n if (/^\\//.test(regex)) {\n re = regex.match(/\\/(.*)\\//).pop();\n flags = regex.replace('/' + re + '/', '');\n\n tested = new RegExp(re, flags).test(urlVal)\n\n } else if ( /^validator\\:\\:/.test(regex) ) {\n /**\n * \"requirements\" : {\n * \"id\" : \"/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\",\n * \"email\": \"validator::{ isEmail: true, isString: [7] }\"\n * }\n * \n * e.g.: tested = new Validator('routing', _data, null, {email: {isEmail: true}} ).isEmail().valid;\n */ \n _data = {}; _ruleObj = {}; _rule = {}; str = ''; \n urlVar.replace( new RegExp('[^'+ key[0] +']','g'), function(){ str += arguments[0] }); \n _data[key[0]] = urlVal.replace( new RegExp(str, 'g'), '');\n _ruleObj = JSON.parse(regex.split(/::/).splice(1)[0].replace(/([^\\W+ true false])+(\\w+)/g, '\"$&\"')); \n _rule[key[0]] = _ruleObj; \n _validator = new Validator('routing', _data, null, _rule );\n \n for (let rule in _ruleObj) {\n if (Array.isArray(_ruleObj[rule])) { // has args\n _validator[key[0]][rule].apply(_validator[key[0]], _ruleObj[rule])\n } else {\n _validator[key[0]][rule](_ruleObj[rule])\n } \n }\n tested = _validator.isValid();\n } else {\n tested = new RegExp(params.requirements[key[0]]).test(urlVal)\n }\n\n if (tested) {\n values[keys[0].substr(1)] = urlVal\n } else {\n return false\n }\n\n strVal = '';\n started = false;\n i = (tplUrl.indexOf(keys[0]) + keys[0].length);\n c -= 1;\n\n keys.splice(0, 1)\n } else {\n strVal += url.charAt(c);\n ++i\n }\n\n if (c == posLen - 1) {\n\n regex = params.requirements[keys[0]];\n urlVal = strVal.substr(0, strVal.length);\n\n if (/^\\//.test(regex)) {\n re = regex.match(/\\/(.*)\\//).pop();\n flags = regex.replace('/' + re + '/', '');\n\n tested = new RegExp(re, flags).test(urlVal)\n\n } else {\n tested = new RegExp(params.requirements[key]).test(urlVal)\n }\n\n if (tested) {\n values[keys[0].substr(1)] = urlVal\n } else {\n return false\n }\n }\n }\n\n if (values.count() == keys.length) {\n key = null;\n for (key in values) {\n request.params[key] = values[key];\n }\n return true\n }\n }\n\n return false\n }\n \n var replacement = function(matched){\n return ( /\\/$/.test(matched) ? replacement.variable+ '/': replacement.variable ) \n };\n var checkRouteParams = function(route, params) {\n var variable = null\n , regex = null\n , urls = null\n , i = null\n , len = null\n , rawRouteUrl = route.url\n , p = null\n , pLen = null\n ;\n for (p in route.param) {\n if ( typeof(params) != 'undefined' && typeof(params[p]) == 'undefined' ) continue;\n \n if ( /^:/.test(route.param[p]) ) {\n variable = route.param[p].substr(1);\n \n if ( typeof(params) != 'undefined' && typeof(params[variable]) != 'undefined' ) {\n \n regex = new RegExp('(:'+variable+'/|:'+variable+'$)', 'g'); \n \n\n if ( typeof(route.param.path) != 'undefined' && /:/.test(route.param.path) ) {\n route.param.path = route.param.path.replace( regex, params[variable]);\n }\n if (typeof (route.param.title) != 'undefined' && /:/.test(route.param.title)) {\n route.param.title = route.param.title.replace( regex, params[variable]);\n }\n if (typeof (route.param.namespace) != 'undefined' && /:/.test(route.param.namespace)) {\n route.param.namespace = route.param.namespace.replace( regex, params[variable]);\n }\n // file is handle like url replacement (path is like pathname)\n if (typeof (route.param.file) != 'undefined' && /:/.test(route.param.file)) {\n replacement.variable = params[variable]; \n route.param.file = route.param.file.replace( regex, replacement );\n }\n \n if ( /\\,/.test(route.url) ) { \n urls = route.url.split(/\\,/g);\n i = 0; len = urls.length;\n for (; i < len; ++i) {\n replacement.variable = params[variable]; \n urls[i] = urls[i].replace( regex, replacement );\n }\n route.url = urls.join(',');\n } else { \n replacement.variable = params[variable]; \n route.url = route.url.replace( regex, replacement );\n }\n }\n }\n }\n \n // Selecting url in case of multiple urls & optional requirmements\n if ( urls ) { \n i = 0; len = urls.length;\n var rawUrlVars = null\n , rawUrlScore = null\n , rawUrls = rawRouteUrl.split(/\\,/g)\n , pKey = null\n , lastScore = 0\n ;\n route.urlIndex = 0; // by default\n for (; i < len; ++i) {\n rawUrlScore = 0;\n rawUrlVars = rawUrls[0].match(/\\:[-_a-z0-9]+/ig);\n if ( !rawUrlVars ) continue;\n p = 0;\n pLen = rawUrlVars.length;\n for (; p < pLen; p++) {\n pKey = rawUrlVars[p].substr(1);\n if ( typeof(params[ pKey ]) != 'undefined' && params[ pKey ] ) {\n rawUrlScore++;\n }\n }\n // We just rely in params count for now\n if (rawUrlScore > lastScore) {\n lastScore = rawUrlScore;\n route.urlIndex = i;\n }\n }\n } \n \n return route;\n }\n\n /**\n * @function getRoute\n *\n * @param {string} rule e.g.: [ <scheme>:// ]<name>[ @<bundle> ][ /<environment> ]\n * @param {object} params\n * @param {number} [urlIndex] in case you have more than one url registered for the current route, you can select the one you want to use. Default is 0.\n *\n * @return {object} route\n * */\n self.getRoute = function(rule, params, urlIndex) {\n \n var config = null;\n if (isGFFCtx) {\n config = window.gina.config;\n } else {\n config = getContext('gina').config;\n if ( typeof(getContext('argvFilename')) != 'undefined' ) {\n config.getRouting = getContext('gina').Config.instance.getRouting;\n }\n }\n \n var env = config.env || GINA_ENV // by default, takes the current bundle\n , envTmp = null\n //, scheme = null\n , bundle = config.bundle // by default, takes the current bundle\n ;\n \n if ( !/\\@/.test(rule) && typeof(bundle) != 'undefined' && bundle != null) {\n rule = rule.toLowerCase()\n rule += '@' + bundle\n }\n\n if ( /\\@/.test(rule) ) {\n\n var arr = ( rule.replace(/(.*)\\:\\/\\//, '') ).split(/\\@/);\n\n bundle = arr[1];\n\n // getting env\n if ( /\\/(.*)$/.test(rule) ) {\n envTmp = ( rule.replace(/(.*)\\:\\/\\//, '') ).split(/\\/(.*)$/)[1];\n bundle = bundle.replace(/\\/(.*)$/, '');\n env = envTmp || env;\n }\n\n\n // getting scheme\n //scheme = ( /\\:\\/\\//.test(rule) ) ? rule.split(/\\:\\/\\//)[0] : config.bundlesConfiguration.conf[bundle][env].server.scheme;\n\n rule = arr[0].toLowerCase() +'@'+ bundle;\n }\n \n \n var routing = config.getRouting(bundle, env);\n\n if ( typeof(routing[rule]) == 'undefined' ) {\n throw new Error('[ RoutingHelper::getRouting(rule, params) ] : `' +rule + '` not found !')\n }\n\n var route = JSON.clone(routing[rule]);\n var variable = null\n , regex = null\n , urls = null\n , i = null\n , len = null\n , msg = null\n ;\n route = checkRouteParams(route, params);\n\n if ( /\\,/.test(route.url) ) {\n if ( typeof(route.urlIndex) != 'undefined' ) {\n urlIndex = route.urlIndex; // set by checkRouteParams(route, params)\n delete route.urlIndex;\n }\n urlIndex = ( typeof(urlIndex) != 'undefined' ) ? urlIndex : 0;\n route.url = route.url.split(/,/g)[urlIndex]; \n }\n // fix url in case of empty param value allowed by the routing rule\n // to prevent having a folder.\n // eg.: {..., id: '/^\\\\s*$/'} => {..., id: ''} => /path/to/ becoming /path/to\n if ( /\\/$/.test(route.url) && route.url != '/' )\n route.url = route.url.substr(0, route.url.length-1);\n \n // Completeting url with extra params e.g.: ?param1=val1&param2=val2\n if ( /GET/i.test(route.method) && typeof(params) != 'undefined' ) {\n var queryParams = '?', maskedUrl = routing[rule].url;\n //self.reservedParams;\n for (let r in route.param) {\n if ( self.reservedParams.indexOf(r) > -1 || new RegExp(route.param[r]).test(maskedUrl) )\n continue;\n if (typeof(params[r]) != 'undefined' )\n queryParams += r +'='+ encodeURIComponent(params[r])+ '&';\n }\n \n if (queryParams.length > 1) {\n queryParams = queryParams.substring(0, queryParams.length-1);\n route.url += queryParams;\n }\n }\n \n // recommanded for x-bundle coms\n // leave `ignoreWebRoot` empty or set it to false for x-bundle coms\n route.toUrl = function (ignoreWebRoot) {\n \n var urlProps = null;\n if ( /^redirect$/i.test(this.param.control) ) {\n urlProps = self.getUrlProps(this.bundle, (env||GINA_ENV));\n }\n \n var wroot = this.webroot || urlProps.webroot\n , hostname = this.hostname || urlProps.hostname\n , path = this.url\n ;\n \n this.url = ( typeof(ignoreWebRoot) != 'undefined' && ignoreWebRoot == true ) ? path.replace(wroot, '/') : path;\n\n return hostname + this.url\n };\n \n /**\n * request current url\n * \n * \n * \n * @param {boolean} [ignoreWebRoot]\n * @param {object} [options] - see: https://nodejs.org/api/https.html#https_new_agent_options\n * @param {object} [_this] - current context: only used when `promisify`is used\n * \n * @callback {callback} [cb] - see: https://nodejs.org/api/https.html#https_new_agent_options\n * @param {object} res\n */\n route.request = function(ignoreWebRoot, options) {\n \n var cb = null, _this = null;\n if ( typeof(arguments[arguments.length-1]) == 'function' ) {\n cb = arguments[arguments.length-1];\n }\n if ( typeof(arguments[2]) == 'object' ) {\n _this = arguments[2];\n }\n \n var wroot = this.webroot || _this.webroot\n , hostname = this.hostname || _this.hostname\n , url = ( typeof(ignoreWebRoot) != 'undefined' && ignoreWebRoot == true ) ? path.replace(wroot, '/') : this.url || _this.url\n ;\n \n var scheme = ( /^https/.test(hostname) ) ? 'https' : 'http';\n \n if (isGFFCtx) {\n var target = ( typeof(options) != 'undefined' && typeof(options.target) != 'undefined' ) ? options.target : \"_self\";\n window.open(url, target)\n } else {\n if ( typeof(options.agent) == 'undefined' ) {\n // See.: https://nodejs.org/api/http.html#http_class_http_agent\n // create an agent just for this request\n options.agent = false;\n }\n var agent = require(''+scheme); \n var onAgentResponse = function(res) { \n \n var data = '', err = false;\n \n res.on('data', function (chunk) {\n data += chunk;\n });\n res.on('error', function (error) {\n err = 'Failed to get mail content';\n if (error && typeof(error.stack) != 'undefined' ) {\n err += error.stack;\n } else if ( typeof(error) == 'string' ) {\n err += '\\n' + error;\n }\n });\n res.on('end', function () {\n if (/^\\{/.test(data) ) {\n try {\n data = JSON.parse(data);\n if (typeof(data.error) != 'undefined') {\n err = JSON.clone(data);\n data = null;\n }\n } catch(parseError) {\n err = parseError\n }\n }\n if (err) { \n cb(err);\n return;\n }\n \n cb(false, data);\n return;\n });\n }\n if (cb) { \n agent.get(url, options, onAgentResponse);\n } else {\n // just throw the request without waiting/handling response\n agent.get(url, options);\n } \n }\n return; \n \n } // EO route.request()\n \n if ( /\\:/.test(route.url) ) {\n var paramList = route.url\n .match(/(\\:(.*)\\/|\\:(.*)$)/g)\n .map(function(el){ return el.replace(/\\//g, ''); }).join(', ');\n msg = '[ RoutingHelper::getRoute(rule[, bundle, method]) ] : route [ %r ] param placeholder not defined: `' + route.url + '` !\\n Check your route description to compare requirements against param variables [ '+ paramList +']';\n msg = msg.replace(/\\%r/, rule);\n var err = new Error(msg);\n console.warn( err );\n // Do not throw error nor return here !!!\n }\n\n return route\n };\n\n var getFormatedRoute = function(route, url, hash) {\n // fix url in case of empty param value allowed by the routing rule\n // to prevent having a folder.\n // eg.: {..., id: '/^\\\\s*$/'} => {..., id: ''} => /path/to/ becoming /path/to\n if ( /\\/$/.test(url) && url != '/' )\n url = url.substr(0, url.length-1);\n // adding hash if found\n if (hash)\n url += hash;\n \n route.url = url;\n // recommanded for x-bundle coms\n // leave `ignoreWebRoot` empty or set it to false for x-bundle coms\n route.toUrl = function (ignoreWebRoot) { \n var wroot = this.webroot\n , hostname = this.hostname\n , path = this.url\n ;\n \n this.url = ( typeof(ignoreWebRoot) != 'undefined' && ignoreWebRoot == true ) ? path.replace(wroot, '/') : path;\n\n return hostname + this.url\n };\n \n return route\n }\n\n /**\n * Get route by url\n * N.B.: this will only work with rules declared with `GET` method property\n *\n * @function getRouteByUrl\n *\n * @param {string} url e.g.: /webroot/some/url/path or http\n * @param {string} [bundle] targeted bundle\n * @param {string} [method] request method (GET|PUT|PUT|DELETE) - GET is set by default\n * @param {object} [request] \n * @param {boolean} [isOverridinMethod] // will replace request.method by the provided method - Used for redirections\n * \n * @return {object|boolean} route - when route is found; `false` when not found\n * */\n \n self.getRouteByUrl = function (url, bundle, method, request, isOverridinMethod) {\n \n if (\n arguments.length == 2 \n && typeof(arguments[1]) != 'undefined' \n && self.allowedMethods.indexOf(arguments[1].toLowerCase()) > -1 \n ) {\n method = arguments[1];\n bundle = undefined;\n }\n var webroot = null\n , route = null\n , routing = null\n , reverseRouting = null\n , hash = null // #section nav\n , hostname = null\n , host = null\n ;\n \n if ( /\\#/.test(url) && url.length > 1 ) {\n var urlPart = url.split(/\\#/);\n url = urlPart[0];\n hash = '#' + urlPart[1];\n \n urlPart = null;\n }\n \n // fast method\n if (\n arguments.length == 1 \n && typeof(arguments[0]) != 'undefined' \n ) {\n if ( !/^(https|http)/i.test(url) && !/^\\//.test(url)) {\n url = '/'+ url;\n }\n \n webroot = '/' + url.split(/\\//g)[1];\n if (isGFFCtx) {\n reverseRouting = gina.config.reverseRouting;\n routing = gina.config.routing\n }\n // get bundle\n if ( typeof(reverseRouting[webroot]) != 'undefined' ) {\n var infos = routing[ reverseRouting[webroot] ];\n bundle = infos.bundle;\n webroot = infos.webroot;\n host = infos.host;\n hostname = infos.hostname;\n infos = null;\n } \n }\n \n isOverridinMethod = ( typeof(arguments[arguments.length-1]) != 'boolean') ? false : arguments[arguments.length-1];\n\n var matched = false \n , config = null\n , env = null\n , prefix = null\n , pathname = null\n , params = null\n , isRoute = null\n , foundRoute = null \n , routeObj = null \n ;\n \n \n \n var isMethodProvidedByDefault = ( typeof(method) != 'undefined' ) ? true : false;\n\n if (isGFFCtx) {\n config = window.gina.config;\n bundle = (typeof (bundle) != 'undefined') ? bundle : config.bundle;\n env = config.env;\n routing = routing || config.getRouting(bundle);\n reverseRouting = reverseRouting || config.reverseRouting;\n isXMLRequest = ( typeof(isXMLRequest) != 'undefined' ) ? isXMLRequest : false; // TODO - retrieve the right value\n\n hostname = hostname || config.hostname;\n webroot = webroot || config.webroot;\n prefix = hostname + webroot;\n\n request = {\n routing: {},\n method: method,\n params: {},\n url: url\n };\n } else {\n\n var gnaCtx = getContext('gina');\n \n config = gnaCtx.config;\n bundle = (typeof (bundle) != 'undefined') ? bundle : config.bundle;\n env = config.env;\n routing = config.getRouting(bundle);\n \n \n\n hostname = config.envConf[bundle][env].hostname;\n webroot = config.envConf[bundle][env].server.webroot;\n prefix = hostname + webroot;\n \n if ( !request ) {\n request = {\n routing: {},\n isXMLRequest: false,\n method : ( typeof(method) != 'undefined' ) ? method.toLowerCase() : 'get',\n params: {},\n url: url\n }\n }\n if (isOverridinMethod) {\n request.method = method;\n }\n isXMLRequest = request.isXMLRequest || false;\n }\n\n pathname = url.replace( new RegExp('^('+ hostname +'|'+hostname.replace(/\\:\\d+/, '') +')' ), '');\n if ( typeof(request.routing.path) == 'undefined' )\n request.routing.path = unescape(pathname);\n method = ( typeof(method) != 'undefined' ) ? method.toLowerCase() : 'get';\n \n if (isMethodProvidedByDefault) {\n // to handle 303 redirect like PUT -> GET\n request.originalMethod = request.method;\n \n request.method = method;\n request.routing.path = unescape(pathname)\n }\n // last method check\n if ( !request.method)\n request.method = method;\n\n // getting params\n params = {};\n \n \n\n var paramsList = null;\n var re = new RegExp(method, 'i');\n var localMethod = null;\n // N.B.: this part of the code must remain identical to the one used in `server.js`\n out:\n for (var name in routing) {\n if (typeof (routing[name]['param']) == 'undefined')\n break;\n\n // bundle filter\n if (routing[name].bundle != bundle) continue;\n\n // method filter\n localMethod = routing[name].method; \n if ( /\\,/.test( localMethod ) && re.test(localMethod) ) {\n localMethod = request.method\n } \n if (typeof (routing[name].method) != 'undefined' && !re.test(localMethod)) continue;\n \n //Preparing params to relay to the core/router. \n params = {\n method : localMethod,\n requirements : routing[name].requirements,\n namespace : routing[name].namespace || undefined,\n url : unescape(pathname), /// avoid %20\n rule : routing[name].originalRule || name,\n param : routing[name].param,\n //middleware: routing[name].middleware,\n middleware : JSON.clone(routing[name].middleware),\n bundle : routing[name].bundle,\n isXMLRequest : isXMLRequest\n };\n\n // normal case\n //Parsing for the right url.\n try { \n \n isRoute = self.compareUrls(params, routing[name].url, request);\n\n if (isRoute.past) {\n\n route = JSON.clone(routing[name]);\n route.name = name;\n\n matched = true;\n isRoute = {};\n\n break;\n }\n\n } catch (err) {\n throw new Error('Route [ ' + name + ' ] needs your attention.\\n' + err.stack);\n }\n } //EO for break out\n\n if (!matched) {\n if (isGFFCtx) { \n var urlHasChanged = false; \n if ( \n url == '#' \n && /GET/i.test(method) \n && isMethodProvidedByDefault \n || /^404\\:/.test(url)\n ) {\n url = location.pathname;\n urlHasChanged = true;\n }\n \n if ( typeof(self.notFound) == 'undefined' ) {\n self.notFound = {}\n }\n \n var notFound = null, msg = '[ RoutingHelper::getRouteByUrl(rule[, bundle, method]) ] : route [ %r ] is called but not found inside your view: `' + url + '` !';\n if ( gina.hasPopinHandler && gina.popinIsBinded ) {\n notFound = gina.popin.getActivePopin().target.innerHTML.match(/404\\:\\[\\w+\\][a-z 0-9-_@]+/);\n } else {\n notFound = document.body.innerHTML.match(/404\\:\\[\\w+\\][a-z 0-9-_@]+/);\n }\n \n notFound = (notFound && notFound.length > 0) ? notFound[0] : null;\n \n if ( notFound && isMethodProvidedByDefault && urlHasChanged ) {\n \n var m = notFound.match(/\\[\\w+\\]/)[0]; \n \n notFound = notFound.replace('404:'+m, m.replace(/\\[|\\]/g, '')+'::' );\n \n msg = msg.replace(/\\%r/, notFound.replace(/404\\:\\s+/, ''));\n \n if (typeof(self.notFound[notFound]) == 'undefined') {\n self.notFound[notFound] = { \n count: 1,\n message: msg \n };\n } else if ( isMethodProvidedByDefault && typeof(self.notFound[notFound]) != 'undefined' ) {\n ++self.notFound[notFound].count;\n }\n \n return false \n } \n \n notFound = null; \n \n var altRule = gina.config.reverseRouting[url] || null; \n if (\n !notFound \n && altRule\n && typeof(altRule) != 'undefined'\n && altRule.split(/\\@(.+)$/)[1] == bundle\n ) {\n \n notFound = altRule;\n if ( typeof(self.notFound[notFound]) == 'undefined' ) {\n \n msg = msg.replace(/\\%r/, method.toUpperCase() +'::'+ altRule);\n \n self.notFound[notFound] = { \n count: 1,\n message: msg \n };\n //console.warn(msg); \n } else if ( isMethodProvidedByDefault && typeof(self.notFound[notFound]) != 'undefined' ) {\n ++self.notFound[notFound].count;\n }\n \n return false\n }\n \n // forms\n var altRoute = self.compareUrls(params, url, request) || null;\n if(altRoute.past && isMethodProvidedByDefault) {\n notFound = method.toUpperCase() +'::'+ altRoute.request.routing.rule;\n if ( typeof(self.notFound[notFound]) == 'undefined' ) {\n msg = msg.replace(/\\%r/, notFound);\n //console.warn(msg); \n } else {\n ++self.notFound[notFound].count;\n }\n \n return false\n } \n return false\n }\n\n \n console.warn( new Error('[ RoutingHelper::getRouteByUrl(rule[, bundle, method, request]) ] : route not found for url: `' + url + '` !').stack ); \n return false;\n } else {\n // fix url in case of empty param value allowed by the routing rule\n // to prevent having a folder.\n // eg.: {..., id: '/^\\\\s*$/'} => {..., id: ''} => /path/to/ becoming /path/to\n if ( /\\/$/.test(url) && url != '/' )\n url = url.substr(0, url.length-1);\n // adding hash if found\n if (hash)\n url += hash;\n \n route.url = url;\n // recommanded for x-bundle coms\n // leave `ignoreWebRoot` empty or set it to false for x-bundle coms\n route.toUrl = function (ignoreWebRoot) { \n var wroot = this.webroot\n , hostname = this.hostname\n , path = this.url\n ;\n \n this.url = ( typeof(ignoreWebRoot) != 'undefined' && ignoreWebRoot == true ) ? path.replace(wroot, '/') : path;\n \n return hostname + this.url\n };\n \n return route\n }\n }\n\n return self\n}\n\nif ((typeof (module) !== 'undefined') && module.exports) {\n // Publish as node.js module\n module.exports = Routing()\n} else if (typeof (define) === 'function' && define.amd) {\n // Publish as AMD module \n define('utils/routing', ['require', 'utils/form-validator', 'utils/merge'], function() { return Routing() })\n};\n",
41
+ "/*\n * This file is part of the gina package.\n * Copyright (c) 2009-2023 Rhinostone <contact@gina.io>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * Routing\n *\n * @package Gina.Lib\n * @namespace Gina.Lib.Routing\n * @author Rhinostone <contact@gina.io>\n * */\n\nfunction Routing() {\n\n var isGFFCtx = ((typeof (module) !== 'undefined') && module.exports) ? false :  true;\n var self = {\n allowedMethods: ['get', 'post', 'put', 'delete'],\n reservedParams: ['controle', 'file','title', 'namespace', 'path'],\n notFound: {}\n }; \n \n self.allowedMethodsString = self.allowedMethods.join(',');\n \n // loading utils & plugins\n var plugins = null, inherits = null, merge = null, Validator = null, fs = null, promisify = null;\n if (!isGFFCtx) {\n fs = require('fs');\n promisify = require('util').promisify;\n inherits = require('../../inherits');\n merge = require('../../merge');\n plugins = require(__dirname+'/../../../core/plugins') || getContext('gina').plugins;\n Validator = plugins.Validator;\n \n } \n // BO - In case of partial rendering whithout handler defined for the partial\n else {\n if ( !merge || typeof(merge) != 'function' ) {\n var merge = require('utils/merge');\n }\n if ( !Validator || typeof(Validator) != 'function' ) {\n var Validator = require('utils/form-validator');\n }\n } \n // EO - In case of partial rendering whithout handler defined for the partial\n \n /**\n * Get url props\n * Used to retrieve additional properties for routes with redirect flag for example\n * \n * @param {string} [bundle]\n * @param {string} [env] \n * \n * @return {object} urlProps - { .host, .hostname, .webroot }\n */\n self.getUrlProps = function(bundle, env) {\n var config = null, urlProps = {}, _route = null;\n if (isGFFCtx) {\n // TODO - add support to get from env\n config = window.gina.config;\n // by default\n urlProps.hostname = config.hostname;\n if ( typeof(bundle) != 'undefined' ) {\n // get from webroot\n _route = routing.getRoute('webroot@'+ bundle);\n urlProps.hostname = _route.hostname;\n urlProps.host = _route.host;\n urlProps.webroot = _route.webroot;\n } \n } else {\n config = getContext('gina').config;\n if ( typeof(getContext('argvFilename')) != 'undefined' ) {\n config.getRouting = getContext('gina').Config.instance.getRouting\n }\n if ( typeof(bundle) == 'undefined' ) {\n bundle = config.bundle;\n }\n if ( typeof(env) == 'undefined' ) {\n env = config.env;\n }\n \n urlProps.hostname = config.envConf[bundle][env].hostname;\n urlProps.host = config.envConf[bundle][env].host;\n urlProps.webroot = config.envConf[bundle][env].server.webroot;\n }\n \n return urlProps;\n }\n \n /**\n * Load bundle routing configuration\n * \n * @param {object} options\n * {\n * isStadalone: false,\n * bundle: 'default', // bundle's name\n * wroot: '/', // by default\n * \n * }\n * \n */\n // self.loadBundleRoutingConfiguration = function(options, filename) {\n \n // }\n \n /**\n * Get routing\n * \n * @param {string} [bundle]\n */\n // self.getRouting = function(bundle) {\n \n // }\n \n /**\n * Get reversed routing\n * \n * @param {string} [bundle]\n */\n // self.getReverseRouting = function(bundle) {\n \n // }\n\n /**\n * Compare urls\n *\n * @param {object} params - Route params containing the given url to be compared with\n * @param {string|array} url - routing.json url\n * @param {object} [request]\n * @param {object} [response] - only used for query validation\n * @param {object} [next] - only used for query validation\n *\n * @return {object|false} foundRoute\n * */\n self.compareUrls = async function(params, url, request, response, next) {\n \n if ( typeof(request) == 'undefined' ) {\n request = { routing: {} };\n }\n // Sample debug break for specific rule\n // if ( params.rule == 'my-specific-rule@bundle' ) {\n // console.debug('passed '+ params.rule);\n // }\n if ( /\\,/.test(url) ) {\n var i = 0\n , urls = url.split(/\\,/g)\n , len = urls.length\n , foundRoute = {\n past: false,\n request: request\n };\n\n\n while (i < len && !foundRoute.past) {\n foundRoute = await parseRouting(params, urls[i], request, response, next);\n ++i;\n }\n\n return foundRoute;\n } else {\n return await parseRouting(params, url, request, response, next);\n }\n };\n\n /**\n * Check if rule has params\n *\n * @param {string} pathname\n * @return {boolean} found\n *\n * @private\n * */\n var hasParams = function(pathname) {\n return (/:/.test(pathname)) ? true : false;\n };\n\n /**\n * Parse routing for mathcing url\n *\n * @param {object} params - `params` is the same `request.routing` that can be retried in controller with: req.routing\n * @param {string} url\n * @param {object} request\n * @param {object} [response] - Only used for query validation\n * @param {object} [next] - Only used for query validation\n *\n * @return {object} foundRoute\n *\n * */\n var parseRouting = async function(params, url, request, response, next) {\n \n // Sample debug break for specific rule\n // if ( params.rule == 'my-specific-rule@bundle' ) {\n // console.debug('passed '+ params.rule);\n // }\n \n var uRe = params.url.split(/\\//)\n , uRo = url.split(/\\//)\n , uReCount = 0\n , uRoCount = 0\n , maxLen = uRo.length\n , score = 0\n , foundRoute = {}\n , i = 0\n , method = request.method.toLowerCase()\n ;\n \n // TODO - remove comments\n // when requirement is not listed but still validated\n // if ( \n // typeof(params.requirements) != 'undefined' \n // && method == params.method.toLowerCase()\n // //&& /validator\\:\\:/.test(JSON.stringify(params.requirements))\n // ) {\n \n // var requiremements = Object.getOwnPropertyNames(params.requirements);\n // var r = 0;\n // // In order to filter variables\n // var uRoVars = uRo.join(',').match(/\\:[-_a-z0-9]+/g);\n // // var uRoVarCount = (uRoVars) ? uRoVars.length : 0;\n // while ( r < requiremements.length ) {\n \n // // if not listed, but still needing validation\n // if ( \n // typeof(params.param[ requiremements[r] ]) == 'undefined' \n // && /^validator\\:\\:/i.test(params.requirements[ requiremements[r] ])\n // && typeof(request[method][ requiremements[r] ])\n // ) {\n // if (uRo.length != uRe.length) {\n // // r++; \n // // continue;\n // break;\n // }\n // // updating uRoVars\n // uRoVars = uRo.join(',').match(/\\:[-_a-z0-9]+/g);\n // /**\n // * \"requirements\" : {\n // * \"email\": \"validator::{ isEmail: true, isString: [7] }\"\n // * }\n // * \n // * e.g.: result = new Validator('routing', _data, null, {email: {isEmail: true, subject: \\\"Anything\\\"}} ).isEmail().valid;\n // */ \n // let regex = params.requirements[ requiremements[r] ];\n // let _data = {}, _ruleObj = {}, _rule = {};\n \n // try {\n // _ruleObj = JSON.parse(\n // regex.split(/::/).splice(1)[0]\n // .replace(/([^\\:\\\"\\s+](\\w+))\\:/g, '\"$1\":') // { query: { validIf: true }} => { \"query\": { \"validIf\": true }}\n // .replace(/([^\\:\\\"\\s+](\\w+))\\s+\\:/g, '\"$1\":') // note the space between `validIf` & `:` { query: { validIf : true }} => { \"query\": { \"validIf\": true }}\n // ); \n // } catch (err) {\n // throw err;\n // }\n \n // let key = requiremements[r];\n // // validator.query case\n // if (typeof(_ruleObj.query) != 'undefined' && typeof(_ruleObj.query.data) != 'undefined') {\n // _data = _ruleObj.query.data;\n // // filter _data vs uRoVars by removing from data those not present in uRoVars\n // for (let k in _data) {\n // if ( uRoVars.indexOf(_data[k]) < 0 ) {\n // delete _data[k]\n // }\n // }\n // for (let p = 0, pLen = uRo.length; p < pLen; p++) {\n // // :variable only\n // if (!/^\\:/.test(uRo[p])) continue;\n \n // let pName = uRo[p].replace(/^\\:/, '');\n // if ( pName != '' && typeof(uRe[p]) != 'undefined' ) {\n // _data[ pName ] = uRe[p];\n // // Updating params\n // if ( typeof(request.params[pName]) == 'undefined' ) {\n // // Set in case it is not found\n // request.params[pName] = uRe[p];\n // }\n // }\n // } \n // }\n // // normal case\n // _data = merge(_data, request[method]);\n \n // if ( typeof(_data[key]) == 'undefined' ) {\n // // init default value for unlisted variable/param\n // _data[key] = null;\n // }\n \n // _rule[key] = _ruleObj; \n // _validator = new Validator('routing', _data, null, _rule );\n \n // if (_ruleObj.count() == 0 ) {\n // console.error('Route validation failed '+ params.rule);\n // return false;\n // }\n \n // for (let rule in _ruleObj) {\n // let _result = null;\n // if (Array.isArray(_ruleObj[rule])) { // has args\n // _result = await _validator[key][rule].apply(_validator[key], _ruleObj[rule]);\n // } else {\n // _result = await _validator[key][rule](_ruleObj[rule], request, response, next);\n // }\n // //let condition = _ruleObj[rule].validIf.replace(new RegExp('\\\\$isValid'), _result.isValid);\n // // if ( eval(condition)) {\n // if ( !_result.isValid ) {\n // --score;\n // }\n // }\n // }\n // r++\n // }\n // }\n \n // attaching routing description for this request\n var paramMethod = params.method.toLowerCase();\n \n var hasAlreadyBeenScored = false;\n if ( \n typeof(params.requirements) != 'undefined'\n && /get|delete/i.test(method)\n && typeof(request[method]) != 'undefined'\n ||\n // GET request is in fact in this case a DELETE request\n typeof(params.requirements) != 'undefined'\n && /get/i.test(method)\n && /delete/i.test(paramMethod)\n ) { \n if ( /get/i.test(method) && /delete/i.test(paramMethod) ) {\n method = paramMethod;\n }\n // `delete` methods don't have a body\n // So, request.delete is {} by default\n if ( /^(delete)$/i.test(method) && uRe.length === uRo.length ) { \n // just in case\n if ( typeof(request[method]) == 'undefined' ) {\n request[method] = {};\n }\n for (let p = 0, pLen = uRo.length; p < pLen; p++) {\n if (uRe[p] === uRo[p]) { \n ++score; \n continue;\n }\n let _key = uRo[p].substr(1);\n if ( typeof(params.requirements[_key]) == 'undefined' ) {\n continue;\n }\n let condition = params.requirements[_key];\n if ( /^\\//.test(condition) ) {\n condition = condition.substr(1, condition.lastIndexOf('/')-1);\n } else if ( /^validator\\:\\:/.test(condition) && await fitsWithRequirements(uRo[p], uRe[p], params, request, response, next) ) {\n ++score;\n continue;\n }\n if (\n /^:/.test(uRo[p]) \n && typeof(condition) != 'undefined'\n && new RegExp(condition).test(uRe[p])\n ) {\n ++score; \n request[method][uRo[p].substr(1)] = uRe[p]; \n }\n }\n hasAlreadyBeenScored = true; \n } \n \n // Sample debug break for specific rule\n // if ( params.rule == 'my-specific-rule@bundle' ) {\n // console.debug('passed '+ params.rule);\n // }\n for (let p in request[method]) {\n if ( typeof(params.requirements[p]) != 'undefined' && uRo.indexOf(':' + p) < 0 ) {\n uRo[uRoCount] = ':' + p; \n ++uRoCount;\n \n uRe[uReCount] = request[method][p];\n ++uReCount;\n if (!hasAlreadyBeenScored && uRe.length === uRo.length)\n ++maxLen; \n }\n }\n }\n \n \n // Sample debug break for specific rule\n // if ( params.rule == 'my-specific-rule@bundle' ) {\n // console.debug('passed '+ params.rule);\n // }\n \n if (!hasAlreadyBeenScored && uRe.length === uRo.length) {\n \n for (; i < maxLen; ++i) {\n \n if (uRe[i] === uRo[i]) {\n ++score;\n }\n else if (score == i && hasParams(uRo[i]) && await fitsWithRequirements(uRo[i], uRe[i], params, request, response, next)) {\n ++score;\n }\n }\n }\n \n // This test is done to catch `validator::` rules under requirements\n if ( \n typeof(params.requirements) != 'undefined' \n && method == params.method.toLowerCase()\n && !hasAlreadyBeenScored\n && score >= maxLen\n ) {\n \n var requiremements = Object.getOwnPropertyNames(params.requirements);\n var r = 0;\n // In order to filter variables\n var uRoVars = uRo.join(',').match(/\\:[-_a-z0-9]+/g);\n // var uRoVarCount = (uRoVars) ? uRoVars.length : 0;\n while ( r < requiremements.length ) {\n // requirement name as `key`\n let key = requiremements[r];\n // if not listed, but still needing validation\n if ( \n typeof(params.param[ key ]) == 'undefined' \n && /^validator\\:\\:/i.test(params.requirements[ key ])\n ) {\n if (uRo.length != uRe.length) {\n // r++; \n // continue;\n break;\n }\n // updating uRoVars\n uRoVars = uRo.join(',').match(/\\:[-_a-z0-9]+/g);\n /**\n * \"requirements\" : {\n * \"email\": \"validator::{ isEmail: true, isString: [7] }\"\n * }\n * \n * e.g.: result = new Validator('routing', _data, null, {email: {isEmail: true, subject: \\\"Anything\\\"}} ).isEmail().valid;\n */ \n let regex = params.requirements[ key ];\n let _data = {}, _ruleObj = {}, _rule = {};\n \n try {\n _ruleObj = JSON.parse(\n regex.split(/::/).splice(1)[0]\n .replace(/([^\\:\\\"\\s+](\\w+))\\:/g, '\"$1\":') // { query: { validIf: true }} => { \"query\": { \"validIf\": true }}\n .replace(/([^\\:\\\"\\s+](\\w+))\\s+\\:/g, '\"$1\":') // note the space between `validIf` & `:` { query: { validIf : true }} => { \"query\": { \"validIf\": true }}\n ); \n } catch (err) {\n throw err;\n }\n \n // validator.query case\n if (typeof(_ruleObj.query) != 'undefined' && typeof(_ruleObj.query.data) != 'undefined') {\n _data = _ruleObj.query.data;\n // filter _data vs uRoVars by removing from data those not present in uRoVars\n for (let k in _data) {\n if ( uRoVars.indexOf(_data[k]) < 0 ) {\n delete _data[k]\n }\n }\n for (let p = 0, pLen = uRo.length; p < pLen; p++) {\n // :variable only\n if (!/^\\:/.test(uRo[p])) continue;\n \n let pName = uRo[p].replace(/^\\:/, '');\n if ( pName != '' && typeof(uRe[p]) != 'undefined' ) {\n _data[ pName ] = uRe[p];\n // Updating params\n if ( typeof(request.params[pName]) == 'undefined' ) {\n // Set in case if not found\n request.params[pName] = uRe[p];\n }\n }\n } \n }\n \n // If validator.query has data, _data should inherit from request data\n _data = merge(_data, JSON.clone(request[method]) || {} );\n // This test is to initialize query.data[key] to null by default\n if ( typeof(_data[key]) == 'undefined' ) {\n // init default value for unlisted variable/param\n _data[key] = null;\n }\n \n _rule[key] = _ruleObj; \n if (!isGFFCtx) {\n _validator = new Validator('routing', _data, null, _rule );\n } else {\n _validator = new Validator(_data);\n }\n \n if (_ruleObj.count() == 0 ) {\n console.error('Route validation failed '+ params.rule);\n --score;\n r++;\n continue;\n } \n // for each validation rule\n for (let rule in _ruleObj) {\n // updating query.data\n if (typeof(_ruleObj[rule].data) != 'undefined') {\n _ruleObj[rule].data = _data;\n }\n let _result = null;\n if (Array.isArray(_ruleObj[rule])) { // has args\n _result = await _validator[key][rule].apply(_validator[key], _ruleObj[rule]);\n } else {\n _result = await _validator[key][rule](_ruleObj[rule], request, response, next);\n } \n \n //let condition = _ruleObj[rule].validIf.replace(new RegExp('\\\\$isValid'), _result.isValid);\n // if ( eval(condition)) {\n if ( !_result.isValid ) {\n --score;\n if ( typeof(_result.error) != 'undefined' ) {\n throw _result.error;\n }\n }\n }\n }\n r++\n }\n }\n\n foundRoute.past = (score === maxLen) ? true : false;\n \n if (foundRoute.past) {\n // attaching routing description for this request\n //request.routing = params; // can be retried in controller with: req.routing\n // && replacing placeholders\n request.routing = checkRouteParams(params, request[method]);\n foundRoute.request = request;\n }\n \n\n return foundRoute;\n };\n\n /**\n * Fits with requiremements\n * This is for server side use only\n * http://en.wikipedia.org/wiki/Regular_expression\n *\n * @param {string} urlVar\n * @param {string} urlVal\n * @param {object} params\n *\n * @return {boolean} true|false - `true` if it fits\n *\n * @private\n * */\n var fitsWithRequirements = async function(urlVar, urlVal, params, request, response, next) {\n // Sample debug break for specific rule\n // if ( params.rule == 'my-specific-rule@bundle' ) {\n // console.debug('passed '+ params.rule);\n // }\n //var isValid = new Validator('routing', { email: \"contact@gina.io\"}, null, {email: {isEmail: true}} ).isEmail().valid;\n var matched = -1\n , _param = urlVar.match(/\\:\\w+/g)\n , regex = new RegExp(urlVar, 'g')\n , re = null\n , flags = null\n , key = null\n , tested = false\n \n , _validator = null\n , _data = null\n , _ruleObj = null\n , _rule = null\n , rule = null\n , str = null\n // request method\n , requestMethod = request.method.toLowerCase()\n ;\n \n if (!_param.length) return false;\n\n // if custom path, path rewrite\n if (params.param.path && regex.test(params.param.path)) {\n params.param.path = params.param.path.replace(regex, urlVal);\n }\n \n // if custom namespace, namespace rewrite\n if (params.param.namespace && regex.test(params.param.namespace)) { \n params.param.namespace = params.param.namespace.replace(regex, urlVal); \n }\n \n // if custom file, file rewrite\n // if (params.param.file && regex.test(params.param.file)) { \n // params.param.file = params.param.file.replace(regex, urlVal); \n // }\n // file is handle like url replacement (path is like pathname)\n if (typeof (params.param.file) != 'undefined' && /:/.test(params.param.file)) {\n var _regex = new RegExp('(:'+urlVar+'/|:'+urlVar+'$)', 'g'); \n replacement.variable = urlVal; \n params.param.file = params.param.file.replace( _regex, replacement );\n }\n\n // if custom title, title rewrite\n if (params.param.title && regex.test(params.param.title)) { \n params.param.title = params.param.title.replace(regex, urlVal);\n }\n\n if (_param.length == 1) { // fast one\n \n re = new RegExp( _param[0]);\n matched = (_param.indexOf(urlVar) > -1) ? _param.indexOf(urlVar) : false;\n \n if (matched === false ) {\n // In order to support rules defined like :\n // { params.url } => `/section/:name/page:number`\n // { request.url } => `/section/plante/page4`\n //\n // with keys = [ \":name\", \":number\" ]\n \n if ( urlVar.match(re) ) {\n matched = 0;\n }\n }\n \n\n if (matched === false) return matched;\n // filter on method\n if (params.method.toLowerCase() !== requestMethod) return false;\n \n if ( typeof(request[requestMethod]) == 'undefined' ) {\n request[requestMethod] = {}\n }\n\n key = _param[matched].substr(1);\n // escaping `\\` characters\n // TODO - remove comment : all regex requirement must start with `/`\n //regex = ( /\\\\/.test(params.requirements[key]) ) ? params.requirements[key].replace(/\\\\/, '') : params.requirements[key];\n regex = params.requirements[key];\n if (/^\\//.test(regex)) {\n re = regex.match(/\\/(.*)\\//).pop();\n flags = regex.replace('/' + re + '/', ''); \n\n tested = new RegExp(re, flags).test(urlVal)\n } else if ( /^validator\\:\\:/.test(regex) && urlVal) {\n /**\n * \"requirements\" : {\n * \"id\" : \"/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\",\n * \"email\": \"validator::{ isEmail: true, isString: [7] }\"\n * }\n * \n * e.g.: tested = new Validator('routing', _data, null, {email: {isEmail: true, subject: \\\"Anything\\\"}} ).isEmail().valid;\n */ \n _data = {}; _ruleObj = {}; _rule = {}; str = ''; \n urlVar.replace( new RegExp('[^'+ key +']','g'), function(){ str += arguments[0] }); \n _data[key] = urlVal.replace( new RegExp(str, 'g'), '');\n try {\n //_ruleObj = JSON.parse(regex.split(/::/).splice(1)[0].replace(/([^\\W+ true false])+(\\w+)/g, '\"$&\"'));\n _ruleObj = JSON.parse(\n regex.split(/::/).splice(1)[0]\n .replace(/([^\\:\\\"\\s+](\\w+))\\:/g, '\"$1\":') // { query: { validIf: true }} => { \"query\": { \"validIf\": true }}\n .replace(/([^\\:\\\"\\s+](\\w+))\\s+\\:/g, '\"$1\":') // note the space between `validIf` & `:` { query: { validIf : true }} => { \"query\": { \"validIf\": true }}\n ); \n } catch (err) {\n throw err;\n }\n //_ruleObj = JSON.parse(regex.split(/::/).splice(1)[0].replace(/([^\\W+ true false])+(\\w+)/g, '\"$&\"')); \n if (typeof(_ruleObj.query) != 'undefined' && typeof(_ruleObj.query.data) != 'undefined') {\n // since we only have one param\n // :var1 == :var1\n if ( urlVar == _ruleObj.query.data[ Object.keys(_ruleObj.query.data)[0] ] ) {\n _ruleObj.query.data[ Object.keys(_ruleObj.query.data)[0] ] = _data[key];\n // Set in case it is not found\n request.params[key] = _data[key];\n }\n }\n _rule[key] = _ruleObj; \n _validator = new Validator('routing', _data, null, _rule );\n if (_ruleObj.count() == 0 ) {\n console.error('Route validation failed '+ params.rule);\n return false;\n }\n for (let rule in _ruleObj) {\n if (Array.isArray(_ruleObj[rule])) { // has args\n await _validator[key][rule].apply(_validator[key], _ruleObj[rule]);\n } else {\n await _validator[key][rule](_ruleObj[rule], request, response, next);\n } \n }\n tested = _validator.isValid();\n } else {\n tested = new RegExp(params.requirements[key]).test(urlVal);\n }\n\n if (\n typeof(params.param[key]) != 'undefined' &&\n typeof(params.requirements) != 'undefined' &&\n typeof(params.requirements[key]) != 'undefined' &&\n typeof(request.params) != 'undefined' &&\n tested\n ) { \n request.params[key] = urlVal;\n if ( typeof(request[requestMethod][key]) == 'undefined' ) {\n request[requestMethod][key] = urlVal;\n }\n return true;\n }\n\n } else { // slow one\n\n // In order to support rules defined like :\n // { params.url } => `/section/:name/page:number`\n // { request.url } => `/section/plante/page4`\n //\n // with keys = [ \":name\", \":number\" ]\n\n var keys = _param\n , tplUrl = params.url\n , url = request.url\n , values = {}\n , strVal = ''\n , started = false\n , i = 0\n ;\n\n for (var c = 0, posLen = url.length; c < posLen; ++c) {\n if (url.charAt(c) == tplUrl.charAt(i) && !started) {\n ++i\n continue\n } else if (strVal == '') { // start\n\n started = true;\n strVal += url.charAt(c);\n } else if (c > (tplUrl.indexOf(keys[0]) + keys[0].length)) {\n\n regex = params.requirements[keys[0]];\n urlVal = strVal.substr(0, strVal.length);\n\n if (/^\\//.test(regex)) {\n re = regex.match(/\\/(.*)\\//).pop();\n flags = regex.replace('/' + re + '/', '');\n\n tested = new RegExp(re, flags).test(urlVal)\n\n } else if ( /^validator\\:\\:/.test(regex) ) {\n /**\n * \"requirements\" : {\n * \"id\" : \"/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\",\n * \"email\": \"validator::{ isEmail: true, isString: [7] }\"\n * }\n * \n * e.g.: tested = new Validator('routing', _data, null, {email: {isEmail: true}} ).isEmail().valid;\n */ \n _data = {}; _ruleObj = {}; _rule = {}; str = ''; \n urlVar.replace( new RegExp('[^'+ key[0] +']','g'), function(){ str += arguments[0] }); \n _data[key[0]] = urlVal.replace( new RegExp(str, 'g'), '');\n _ruleObj = JSON.parse(regex.split(/::/).splice(1)[0].replace(/([^\\W+ true false])+(\\w+)/g, '\"$&\"')); \n _rule[key[0]] = _ruleObj; \n _validator = new Validator('routing', _data, null, _rule );\n \n for (let rule in _ruleObj) {\n if (Array.isArray(_ruleObj[rule])) { // has args\n _validator[key[0]][rule].apply(_validator[key[0]], _ruleObj[rule])\n } else {\n _validator[key[0]][rule](_ruleObj[rule])\n } \n }\n tested = _validator.isValid();\n } else {\n tested = new RegExp(params.requirements[key[0]]).test(urlVal)\n }\n\n if (tested) {\n values[keys[0].substr(1)] = urlVal\n } else {\n return false\n }\n\n strVal = '';\n started = false;\n i = (tplUrl.indexOf(keys[0]) + keys[0].length);\n c -= 1;\n\n keys.splice(0, 1)\n } else {\n strVal += url.charAt(c);\n ++i\n }\n\n if (c == posLen - 1) {\n\n regex = params.requirements[keys[0]];\n urlVal = strVal.substr(0, strVal.length);\n\n if (/^\\//.test(regex)) {\n re = regex.match(/\\/(.*)\\//).pop();\n flags = regex.replace('/' + re + '/', '');\n\n tested = new RegExp(re, flags).test(urlVal)\n\n } else {\n tested = new RegExp(params.requirements[key]).test(urlVal)\n }\n\n if (tested) {\n values[keys[0].substr(1)] = urlVal\n } else {\n return false\n }\n }\n }\n\n if (values.count() == keys.length) {\n key = null;\n for (key in values) {\n request.params[key] = values[key];\n }\n return true\n }\n }\n\n return false\n }\n \n var replacement = function(matched){\n return ( /\\/$/.test(matched) ? replacement.variable+ '/': replacement.variable ) \n };\n var checkRouteParams = function(route, params) {\n var variable = null\n , regex = null\n , urls = null\n , i = null\n , len = null\n , rawRouteUrl = route.url\n , p = null\n , pLen = null\n ;\n for (p in route.param) {\n if ( typeof(params) != 'undefined' && typeof(params[p]) == 'undefined' ) continue;\n \n if ( /^:/.test(route.param[p]) ) {\n variable = route.param[p].substr(1);\n \n if ( typeof(params) != 'undefined' && typeof(params[variable]) != 'undefined' ) {\n \n regex = new RegExp('(:'+variable+'/|:'+variable+'$)', 'g'); \n \n\n if ( typeof(route.param.path) != 'undefined' && /:/.test(route.param.path) ) {\n route.param.path = route.param.path.replace( regex, params[variable]);\n }\n if (typeof (route.param.title) != 'undefined' && /:/.test(route.param.title)) {\n route.param.title = route.param.title.replace( regex, params[variable]);\n }\n if (typeof (route.param.namespace) != 'undefined' && /:/.test(route.param.namespace)) {\n route.param.namespace = route.param.namespace.replace( regex, params[variable]);\n }\n // file is handle like url replacement (path is like pathname)\n if (typeof (route.param.file) != 'undefined' && /:/.test(route.param.file)) {\n replacement.variable = params[variable]; \n route.param.file = route.param.file.replace( regex, replacement );\n }\n \n if ( /\\,/.test(route.url) ) { \n urls = route.url.split(/\\,/g);\n i = 0; len = urls.length;\n for (; i < len; ++i) {\n replacement.variable = params[variable]; \n urls[i] = urls[i].replace( regex, replacement );\n }\n route.url = urls.join(',');\n } else { \n replacement.variable = params[variable]; \n route.url = route.url.replace( regex, replacement );\n }\n }\n }\n }\n \n // Selecting url in case of multiple urls & optional requirmements\n if ( urls ) { \n i = 0; len = urls.length;\n var rawUrlVars = null\n , rawUrlScore = null\n , rawUrls = rawRouteUrl.split(/\\,/g)\n , pKey = null\n , lastScore = 0\n ;\n route.urlIndex = 0; // by default\n for (; i < len; ++i) {\n rawUrlScore = 0;\n rawUrlVars = rawUrls[0].match(/\\:[-_a-z0-9]+/ig);\n if ( !rawUrlVars ) continue;\n p = 0;\n pLen = rawUrlVars.length;\n for (; p < pLen; p++) {\n pKey = rawUrlVars[p].substr(1);\n if ( typeof(params[ pKey ]) != 'undefined' && params[ pKey ] ) {\n rawUrlScore++;\n }\n }\n // We just rely in params count for now\n if (rawUrlScore > lastScore) {\n lastScore = rawUrlScore;\n route.urlIndex = i;\n }\n }\n } \n \n return route;\n }\n\n /**\n * @function getRoute\n *\n * @param {string} rule e.g.: [ <scheme>:// ]<name>[ @<bundle> ][ /<environment> ]\n * @param {object} params\n * @param {number} [urlIndex] in case you have more than one url registered for the current route, you can select the one you want to use. Default is 0.\n *\n * @return {object} route\n * */\n self.getRoute = function(rule, params, urlIndex) {\n \n var config = null;\n if (isGFFCtx) {\n config = window.gina.config;\n } else {\n config = getContext('gina').config;\n if ( typeof(getContext('argvFilename')) != 'undefined' ) {\n config.getRouting = getContext('gina').Config.instance.getRouting;\n }\n }\n \n var env = config.env || GINA_ENV // by default, takes the current bundle\n , envTmp = null\n //, scheme = null\n , bundle = config.bundle // by default, takes the current bundle\n ;\n \n if ( !/\\@/.test(rule) && typeof(bundle) != 'undefined' && bundle != null) {\n rule = rule.toLowerCase()\n rule += '@' + bundle\n }\n\n if ( /\\@/.test(rule) ) {\n\n var arr = ( rule.replace(/(.*)\\:\\/\\//, '') ).split(/\\@/);\n\n bundle = arr[1];\n\n // getting env\n if ( /\\/(.*)$/.test(rule) ) {\n envTmp = ( rule.replace(/(.*)\\:\\/\\//, '') ).split(/\\/(.*)$/)[1];\n bundle = bundle.replace(/\\/(.*)$/, '');\n env = envTmp || env;\n }\n\n\n // getting scheme\n //scheme = ( /\\:\\/\\//.test(rule) ) ? rule.split(/\\:\\/\\//)[0] : config.bundlesConfiguration.conf[bundle][env].server.scheme;\n\n rule = arr[0].toLowerCase() +'@'+ bundle;\n }\n \n \n var routing = config.getRouting(bundle, env);\n\n if ( typeof(routing[rule]) == 'undefined' ) {\n throw new Error('[ RoutingHelper::getRouting(rule, params) ] : `' +rule + '` not found !')\n }\n\n var route = JSON.clone(routing[rule]);\n var variable = null\n , regex = null\n , urls = null\n , i = null\n , len = null\n , msg = null\n ;\n route = checkRouteParams(route, params);\n\n if ( /\\,/.test(route.url) ) {\n if ( typeof(route.urlIndex) != 'undefined' ) {\n urlIndex = route.urlIndex; // set by checkRouteParams(route, params)\n delete route.urlIndex;\n }\n urlIndex = ( typeof(urlIndex) != 'undefined' ) ? urlIndex : 0;\n route.url = route.url.split(/,/g)[urlIndex]; \n }\n // fix url in case of empty param value allowed by the routing rule\n // to prevent having a folder.\n // eg.: {..., id: '/^\\\\s*$/'} => {..., id: ''} => /path/to/ becoming /path/to\n if ( /\\/$/.test(route.url) && route.url != '/' )\n route.url = route.url.substr(0, route.url.length-1);\n \n // Completeting url with extra params e.g.: ?param1=val1&param2=val2\n if ( /GET/i.test(route.method) && typeof(params) != 'undefined' ) {\n var queryParams = '?', maskedUrl = routing[rule].url;\n //self.reservedParams;\n for (let r in route.param) {\n if ( self.reservedParams.indexOf(r) > -1 || new RegExp(route.param[r]).test(maskedUrl) )\n continue;\n if (typeof(params[r]) != 'undefined' )\n queryParams += r +'='+ encodeURIComponent(params[r])+ '&';\n }\n \n if (queryParams.length > 1) {\n queryParams = queryParams.substring(0, queryParams.length-1);\n route.url += queryParams;\n }\n }\n \n // recommanded for x-bundle coms\n // leave `ignoreWebRoot` empty or set it to false for x-bundle coms\n route.toUrl = function (ignoreWebRoot) {\n \n var urlProps = null;\n if ( /^redirect$/i.test(this.param.control) ) {\n urlProps = self.getUrlProps(this.bundle, (env||GINA_ENV));\n }\n \n var wroot = this.webroot || urlProps.webroot\n , hostname = this.hostname || urlProps.hostname\n , path = this.url\n ;\n \n this.url = ( typeof(ignoreWebRoot) != 'undefined' && ignoreWebRoot == true ) ? path.replace(wroot, '/') : path;\n\n return hostname + this.url\n };\n \n /**\n * request current url\n * \n * \n * \n * @param {boolean} [ignoreWebRoot]\n * @param {object} [options] - see: https://nodejs.org/api/https.html#https_new_agent_options\n * @param {object} [_this] - current context: only used when `promisify`is used\n * \n * @callback {callback} [cb] - see: https://nodejs.org/api/https.html#https_new_agent_options\n * @param {object} res\n */\n route.request = function(ignoreWebRoot, options) {\n \n var cb = null, _this = null;\n if ( typeof(arguments[arguments.length-1]) == 'function' ) {\n cb = arguments[arguments.length-1];\n }\n if ( typeof(arguments[2]) == 'object' ) {\n _this = arguments[2];\n }\n \n var wroot = this.webroot || _this.webroot\n , hostname = this.hostname || _this.hostname\n , url = ( typeof(ignoreWebRoot) != 'undefined' && ignoreWebRoot == true ) ? path.replace(wroot, '/') : this.url || _this.url\n ;\n \n var scheme = ( /^https/.test(hostname) ) ? 'https' : 'http';\n \n if (isGFFCtx) {\n var target = ( typeof(options) != 'undefined' && typeof(options.target) != 'undefined' ) ? options.target : \"_self\";\n window.open(url, target)\n } else {\n if ( typeof(options.agent) == 'undefined' ) {\n // See.: https://nodejs.org/api/http.html#http_class_http_agent\n // create an agent just for this request\n options.agent = false;\n }\n var agent = require(''+scheme); \n var onAgentResponse = function(res) { \n \n var data = '', err = false;\n \n res.on('data', function (chunk) {\n data += chunk;\n });\n res.on('error', function (error) {\n err = 'Failed to get mail content';\n if (error && typeof(error.stack) != 'undefined' ) {\n err += error.stack;\n } else if ( typeof(error) == 'string' ) {\n err += '\\n' + error;\n }\n });\n res.on('end', function () {\n if (/^\\{/.test(data) ) {\n try {\n data = JSON.parse(data);\n if (typeof(data.error) != 'undefined') {\n err = JSON.clone(data);\n data = null;\n }\n } catch(parseError) {\n err = parseError\n }\n }\n if (err) { \n cb(err);\n return;\n }\n \n cb(false, data);\n return;\n });\n }\n if (cb) { \n agent.get(url, options, onAgentResponse);\n } else {\n // just throw the request without waiting/handling response\n agent.get(url, options);\n } \n }\n return; \n \n } // EO route.request()\n \n if ( /\\:/.test(route.url) ) {\n var paramList = route.url\n .match(/(\\:(.*)\\/|\\:(.*)$)/g)\n .map(function(el){ return el.replace(/\\//g, ''); }).join(', ');\n msg = '[ RoutingHelper::getRoute(rule[, bundle, method]) ] : route [ %r ] param placeholder not defined: `' + route.url + '` !\\n Check your route description to compare requirements against param variables [ '+ paramList +']';\n msg = msg.replace(/\\%r/, rule);\n var err = new Error(msg);\n console.warn( err );\n // Do not throw error nor return here !!!\n }\n\n return route\n };\n\n var getFormatedRoute = function(route, url, hash) {\n // fix url in case of empty param value allowed by the routing rule\n // to prevent having a folder.\n // eg.: {..., id: '/^\\\\s*$/'} => {..., id: ''} => /path/to/ becoming /path/to\n if ( /\\/$/.test(url) && url != '/' )\n url = url.substr(0, url.length-1);\n // adding hash if found\n if (hash)\n url += hash;\n \n route.url = url;\n // recommanded for x-bundle coms\n // leave `ignoreWebRoot` empty or set it to false for x-bundle coms\n route.toUrl = function (ignoreWebRoot) { \n var wroot = this.webroot\n , hostname = this.hostname\n , path = this.url\n ;\n \n this.url = ( typeof(ignoreWebRoot) != 'undefined' && ignoreWebRoot == true ) ? path.replace(wroot, '/') : path;\n\n return hostname + this.url\n };\n \n return route\n }\n\n /**\n * Get route by url\n * N.B.: this will only work with rules declared with `GET` method property\n *\n * @function getRouteByUrl\n *\n * @param {string} url e.g.: /webroot/some/url/path or http\n * @param {string} [bundle] targeted bundle\n * @param {string} [method] request method (GET|PUT|PUT|DELETE) - GET is set by default\n * @param {object} [request] \n * @param {boolean} [isOverridinMethod] // will replace request.method by the provided method - Used for redirections\n * \n * @return {object|boolean} route - when route is found; `false` when not found\n * */\n \n self.getRouteByUrl = function (url, bundle, method, request, isOverridinMethod) {\n \n if (\n arguments.length == 2 \n && typeof(arguments[1]) != 'undefined' \n && self.allowedMethods.indexOf(arguments[1].toLowerCase()) > -1 \n ) {\n method = arguments[1];\n bundle = undefined;\n }\n var webroot = null\n , route = null\n , routing = null\n , reverseRouting = null\n , hash = null // #section nav\n , hostname = null\n , host = null\n ;\n \n if ( /\\#/.test(url) && url.length > 1 ) {\n var urlPart = url.split(/\\#/);\n url = urlPart[0];\n hash = '#' + urlPart[1];\n \n urlPart = null;\n }\n \n // fast method\n if (\n arguments.length == 1 \n && typeof(arguments[0]) != 'undefined' \n ) {\n if ( !/^(https|http)/i.test(url) && !/^\\//.test(url)) {\n url = '/'+ url;\n }\n \n webroot = '/' + url.split(/\\//g)[1];\n if (isGFFCtx) {\n reverseRouting = gina.config.reverseRouting;\n routing = gina.config.routing\n }\n // get bundle\n if ( typeof(reverseRouting[webroot]) != 'undefined' ) {\n var infos = routing[ reverseRouting[webroot] ];\n bundle = infos.bundle;\n webroot = infos.webroot;\n host = infos.host;\n hostname = infos.hostname;\n infos = null;\n } \n }\n \n isOverridinMethod = ( typeof(arguments[arguments.length-1]) != 'boolean') ? false : arguments[arguments.length-1];\n\n var matched = false \n , config = null\n , env = null\n , prefix = null\n , pathname = null\n , params = null\n , isRoute = null\n , foundRoute = null \n , routeObj = null \n ;\n \n \n \n var isMethodProvidedByDefault = ( typeof(method) != 'undefined' ) ? true : false;\n\n if (isGFFCtx) {\n config = window.gina.config;\n bundle = (typeof (bundle) != 'undefined') ? bundle : config.bundle;\n env = config.env;\n routing = routing || config.getRouting(bundle);\n reverseRouting = reverseRouting || config.reverseRouting;\n isXMLRequest = ( typeof(isXMLRequest) != 'undefined' ) ? isXMLRequest : false; // TODO - retrieve the right value\n\n hostname = hostname || config.hostname;\n webroot = webroot || config.webroot;\n prefix = hostname + webroot;\n\n request = {\n routing: {},\n method: method,\n params: {},\n url: url\n };\n } else {\n\n var gnaCtx = getContext('gina');\n \n config = gnaCtx.config;\n bundle = (typeof (bundle) != 'undefined') ? bundle : config.bundle;\n env = config.env;\n routing = config.getRouting(bundle);\n \n \n\n hostname = config.envConf[bundle][env].hostname;\n webroot = config.envConf[bundle][env].server.webroot;\n prefix = hostname + webroot;\n \n if ( !request ) {\n request = {\n routing: {},\n isXMLRequest: false,\n method : ( typeof(method) != 'undefined' ) ? method.toLowerCase() : 'get',\n params: {},\n url: url\n }\n }\n if (isOverridinMethod) {\n request.method = method;\n }\n isXMLRequest = request.isXMLRequest || false;\n }\n\n pathname = url.replace( new RegExp('^('+ hostname +'|'+hostname.replace(/\\:\\d+/, '') +')' ), '');\n if ( typeof(request.routing.path) == 'undefined' )\n request.routing.path = unescape(pathname);\n method = ( typeof(method) != 'undefined' ) ? method.toLowerCase() : 'get';\n \n if (isMethodProvidedByDefault) {\n // to handle 303 redirect like PUT -> GET\n request.originalMethod = request.method;\n \n request.method = method;\n request.routing.path = unescape(pathname)\n }\n // last method check\n if ( !request.method)\n request.method = method;\n\n // getting params\n params = {};\n \n \n\n var paramsList = null;\n var re = new RegExp(method, 'i');\n var localMethod = null;\n // N.B.: this part of the code must remain identical to the one used in `server.js`\n out:\n for (var name in routing) {\n if (typeof (routing[name]['param']) == 'undefined')\n break;\n\n // bundle filter\n if (routing[name].bundle != bundle) continue;\n\n // method filter\n localMethod = routing[name].method; \n if ( /\\,/.test( localMethod ) && re.test(localMethod) ) {\n localMethod = request.method\n } \n if (typeof (routing[name].method) != 'undefined' && !re.test(localMethod)) continue;\n \n //Preparing params to relay to the core/router. \n params = {\n method : localMethod,\n requirements : routing[name].requirements,\n namespace : routing[name].namespace || undefined,\n url : unescape(pathname), /// avoid %20\n rule : routing[name].originalRule || name,\n param : routing[name].param,\n //middleware: routing[name].middleware,\n middleware : JSON.clone(routing[name].middleware),\n bundle : routing[name].bundle,\n isXMLRequest : isXMLRequest\n };\n\n // normal case\n //Parsing for the right url.\n try { \n \n isRoute = self.compareUrls(params, routing[name].url, request);\n\n if (isRoute.past) {\n\n route = JSON.clone(routing[name]);\n route.name = name;\n\n matched = true;\n isRoute = {};\n\n break;\n }\n\n } catch (err) {\n throw new Error('Route [ ' + name + ' ] needs your attention.\\n' + err.stack);\n }\n } //EO for break out\n\n if (!matched) {\n if (isGFFCtx) { \n var urlHasChanged = false; \n if ( \n url == '#' \n && /GET/i.test(method) \n && isMethodProvidedByDefault \n || /^404\\:/.test(url)\n ) {\n url = location.pathname;\n urlHasChanged = true;\n }\n \n if ( typeof(self.notFound) == 'undefined' ) {\n self.notFound = {}\n }\n \n var notFound = null, msg = '[ RoutingHelper::getRouteByUrl(rule[, bundle, method]) ] : route [ %r ] is called but not found inside your view: `' + url + '` !';\n if ( gina.hasPopinHandler && gina.popinIsBinded ) {\n notFound = gina.popin.getActivePopin().target.innerHTML.match(/404\\:\\[\\w+\\][a-z 0-9-_@]+/);\n } else {\n notFound = document.body.innerHTML.match(/404\\:\\[\\w+\\][a-z 0-9-_@]+/);\n }\n \n notFound = (notFound && notFound.length > 0) ? notFound[0] : null;\n \n if ( notFound && isMethodProvidedByDefault && urlHasChanged ) {\n \n var m = notFound.match(/\\[\\w+\\]/)[0]; \n \n notFound = notFound.replace('404:'+m, m.replace(/\\[|\\]/g, '')+'::' );\n \n msg = msg.replace(/\\%r/, notFound.replace(/404\\:\\s+/, ''));\n \n if (typeof(self.notFound[notFound]) == 'undefined') {\n self.notFound[notFound] = { \n count: 1,\n message: msg \n };\n } else if ( isMethodProvidedByDefault && typeof(self.notFound[notFound]) != 'undefined' ) {\n ++self.notFound[notFound].count;\n }\n \n return false \n } \n \n notFound = null; \n \n var altRule = gina.config.reverseRouting[url] || null; \n if (\n !notFound \n && altRule\n && typeof(altRule) != 'undefined'\n && altRule.split(/\\@(.+)$/)[1] == bundle\n ) {\n \n notFound = altRule;\n if ( typeof(self.notFound[notFound]) == 'undefined' ) {\n \n msg = msg.replace(/\\%r/, method.toUpperCase() +'::'+ altRule);\n \n self.notFound[notFound] = { \n count: 1,\n message: msg \n };\n //console.warn(msg); \n } else if ( isMethodProvidedByDefault && typeof(self.notFound[notFound]) != 'undefined' ) {\n ++self.notFound[notFound].count;\n }\n \n return false\n }\n \n // forms\n var altRoute = self.compareUrls(params, url, request) || null;\n if(altRoute.past && isMethodProvidedByDefault) {\n notFound = method.toUpperCase() +'::'+ altRoute.request.routing.rule;\n if ( typeof(self.notFound[notFound]) == 'undefined' ) {\n msg = msg.replace(/\\%r/, notFound);\n //console.warn(msg); \n } else {\n ++self.notFound[notFound].count;\n }\n \n return false\n } \n return false\n }\n\n \n console.warn( new Error('[ RoutingHelper::getRouteByUrl(rule[, bundle, method, request]) ] : route not found for url: `' + url + '` !').stack ); \n return false;\n } else {\n // fix url in case of empty param value allowed by the routing rule\n // to prevent having a folder.\n // eg.: {..., id: '/^\\\\s*$/'} => {..., id: ''} => /path/to/ becoming /path/to\n if ( /\\/$/.test(url) && url != '/' )\n url = url.substr(0, url.length-1);\n // adding hash if found\n if (hash)\n url += hash;\n \n route.url = url;\n // recommanded for x-bundle coms\n // leave `ignoreWebRoot` empty or set it to false for x-bundle coms\n route.toUrl = function (ignoreWebRoot) { \n var wroot = this.webroot\n , hostname = this.hostname\n , path = this.url\n ;\n \n this.url = ( typeof(ignoreWebRoot) != 'undefined' && ignoreWebRoot == true ) ? path.replace(wroot, '/') : path;\n \n return hostname + this.url\n };\n \n return route\n }\n }\n\n return self\n}\n\nif ((typeof (module) !== 'undefined') && module.exports) {\n // Publish as node.js module\n module.exports = Routing()\n} else if (typeof (define) === 'function' && define.amd) {\n // Publish as AMD module \n define('utils/routing', ['require', 'utils/form-validator', 'utils/merge'], function() { return Routing() })\n};\n",
42
42
  "/**\n * Gina Local Storage\n * N.B.: this is based on Web StorageAPI & Node LocalStorage\n * See.:\n * - https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API\n * - https://www.npmjs.com/package/node-localstorage\n * */\nfunction StoragePlugin(options) {\n\n var merge = merge || require('utils/merge');;\n var Collection = Collection || require('utils/collection');\n var uuid = uuid || require('vendor/uuid');\n var dateFormat = dateFormat || require('helpers/dateFormat');\n\n\n var self = {\n 'options' : {\n 'bucket': 'default'\n }\n };\n\n var bucketInstance = {};\n var storage = null;\n\n var entities = {}, collections = {}; // entities & collections (data) objects\n var keywords = ['not null']; // TODO - null, exists\n\n\n var proto = {\n 'bucket' : undefined,\n 'drop' : bucketDrop,\n 'Collection': Collection\n };\n\n var entityProto = {\n 'insert' : collectionInsert,\n 'find' : collectionFind,\n 'findOne' : collectionFindOne,\n 'update' : null,\n 'delete' : collectionDelete,\n 'drop' : collectionDrop\n };\n\n var init = function(options) {\n\n // detect if cookies are enabled\n if ( !window.localStorage || window.localStorage && ! typeof(window.localStorage.setItem) == 'undefined' ) {\n throw new Error('Make sure your browser supports `window.localStorage` to use Gina Storage. See: `https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API#Browser_compatibility`');\n }\n\n if ( typeof(options) != 'object' && typeof(options) != 'undefined' ) {\n throw new Error('`options` must be an object')\n } else if ( typeof(options) == 'undefined' ) {\n var options = {}\n }\n\n self.options = merge(options, self.options);\n storage = window.localStorage;\n\n var bucketName = self.options['bucket'];\n var bucket = storage.getItem(bucketName);\n\n if (!bucket && bucketName != undefined) {\n //console.log('creating new bucket !');\n bucketCreate(bucketName);\n } else if (bucketName == undefined) {\n throw new Error('`bucket` name cannot be undefined')\n }\n\n bucketInstance['bucket'] = bucketName;\n bucketInstance = merge(bucketInstance, proto);\n }\n\n\n\n /**\n * Create bucket\n *\n * @param {string} bucketName\n * */\n var bucketCreate = function(bucketName) {\n storage.setItem(bucketName, JSON.stringify(collections));\n }\n\n\n /**\n * Drop bucket\n *\n * */\n function bucketDrop() {\n storage.removeItem(self.options['bucket']);\n bucketInstance = null;\n\n for (var prop in this) {\n delete this[prop]\n }\n\n return bucketInstance;\n }\n\n var collectionSave = function (enforceDeleted) {\n\n var enforceDeleted = enforceDeleted || false;\n\n try {\n //backing up collections\n var tmpCollections = JSON.clone(collections);\n var index = this['_index'];\n var collection = this['_collection'];\n var bucket = this['_bucket'];\n var filter = this['_filter'];\n this['_updatedAt'] = new Date().format(\"isoDateTime\");\n\n merge(tmpCollections[ collection ][ index ], this, true);\n\n // cleaning\n delete tmpCollections[ collection ][ index ]['_index'];\n delete tmpCollections[ collection ][ index ]['_collection'];\n delete tmpCollections[ collection ][ index ]['_bucket'];\n delete tmpCollections[ collection ][ index ]['save'];\n delete tmpCollections[ collection ][ index ]['_filter'];\n\n if (enforceDeleted && typeof(tmpCollections[ collection ][ index ]) == 'object' ) {\n\n var parseEnforcedCollection = function (arr, target) {\n for (var i = 0, len = arr.length; i < len; ++i) {\n if ( typeof (target[i]) == 'object' && typeof(arr[i]) != 'undefined' && !Array.isArray(arr[i]) ) {\n parseEnforced(arr[i], target[i])\n } else if ( !Array.isArray(arr[i]) ){\n if (typeof(arr[i]) == 'undefined') {\n delete target[i]\n }\n } else { // is collection type\n parseEnforcedCollection(arr[i], target[i])\n }\n }\n\n return target\n }\n\n var parseEnforced = function (obj, target) {\n for (var prop in target) {\n if ( typeof (target[prop]) == 'object' && typeof(obj[prop]) != 'undefined' && !Array.isArray(obj[prop]) ) {\n parseEnforced(obj[prop], target[prop])\n } else if ( !Array.isArray(obj[prop]) ){\n if (typeof(obj[prop]) == 'undefined') {\n delete target[ prop ]\n }\n } else { // is collection type\n parseEnforcedCollection(obj[prop], target[prop])\n }\n }\n\n return target\n };\n\n if ( Array.isArray(tmpCollections[ collection ][ index ]) ) {\n tmpCollections[ collection ][ index ] = parseEnforcedCollection(this, tmpCollections[ collection ][ index ])\n } else if ( typeof(tmpCollections[ collection ][ index ] ) == 'object' ) {\n tmpCollections[ collection ][ index ] = parseEnforced(this, tmpCollections[ collection ][ index ])\n } else {\n if (typeof(this[prop]) == 'undefined') {\n delete tmpCollections[ collection ][ index ]\n }\n }\n }\n\n collections[ collection ][ index ] = tmpCollections[ collection ][ index ];\n\n // saving\n storage.setItem(bucket, JSON.stringify(collections));\n\n return collectionFindOne(filter)\n\n } catch (err) {\n throw err\n }\n }\n\n /**\n * Create or Get Collection by name\n *\n * @param {string} name - Collection name\n * */\n function Collection(name) {\n // retrieve collections state\n collections = JSON.parse(storage.getItem(this['bucket']));\n //console.log('collections ', (collections || null) );\n if ( typeof(collections[name]) == 'undefined' ) {\n collections[name] = [];\n storage.setItem(this['bucket'], JSON.stringify(collections));\n collections = JSON.parse(storage.getItem(this['bucket']));\n }\n\n entities[name] = { '_collection': name, '_bucket': this['bucket'] };\n entities[name] = merge(entities[name], entityProto);\n\n return entities[name]\n }\n\n /**\n * Drop collection\n *\n * @param {string} name\n * */\n function collectionDrop(name) {\n if ( typeof(collections[ this['_collection'] ]) == 'undefined' ) {\n throw new Error('Collection `'+name+'` not found')\n }\n\n delete entities[ this['_collection'] ]; // delete entity\n delete collections[ this['_collection'] ]; // delete data\n\n storage.setItem(this['_bucket'], JSON.stringify(collections));\n }\n\n\n /**\n * Insert into collection\n *\n * @param {object} content\n * */\n function collectionInsert(content) {\n\n // TODO - add uuid\n content['_id'] = uuid.v1();\n content['_createdAt'] = new Date().format(\"isoDateTime\");\n content['_updatedAt'] = new Date().format(\"isoDateTime\");\n\n collections[ this['_collection'] ][ collections[ this['_collection'] ].length ] = content;\n\n storage.setItem(this['_bucket'], JSON.stringify(collections));\n }\n\n /**\n * Find from collection\n *\n * // TODO - add options\n *\n * @param {object} filter\n * @param {object} [options] - e.g.: limit\n *\n * @return {array} result\n * */\n function collectionFind(filter, options) {\n if (!filter) {\n // TODO - limit of ten by\n return collections[ this['_collection'] ]\n }\n\n if ( typeof(filter) !== 'object' ) { // == findAll\n throw new Error('filter must be an object');\n } else {\n //console.log('search into ', this['_collection'], collections[ this['_collection'] ], collections);\n var content = collections[ this['_collection'] ]\n , condition = filter.count()\n , i = 0\n , found = []\n , localeLowerCase = '';\n\n for (var o in content) {\n for (var f in filter) {\n localeLowerCase = ( typeof(filter[f]) != 'boolean' ) ? filter[f].toLocaleLowerCase() : filter[f];\n if ( filter[f] && keywords.indexOf(localeLowerCase) > -1 && localeLowerCase == 'not null' && typeof(content[o][f]) != 'undefined' && typeof(content[o][f]) !== 'object' && content[o][f] != 'null' && content[o][f] != 'undefined' ) {\n if (found.indexOf(content[o][f]) < 0 ) {\n found[i] = content[o][f];\n ++i\n }\n\n } else if ( typeof(content[o][f]) != 'undefined' && typeof(content[o][f]) !== 'object' && content[o][f] === filter[f] ) {\n found[i] = content[o];\n ++i\n }\n }\n }\n }\n\n return found\n }\n\n //function collectionLimit(limit) {}\n\n /**\n * Find a single result from collection\n *\n * e.g:\n * // getting a record\n * > var objectRecord = <bucket>.Collection('myBucket').findOne({_name: \"someName\"});\n *\n * // updating record by adding or updating an existing property\n * > objectRecord.myProperty = 'some value';\n * > objectRecord.save();\n *\n * // deleting record\n * > objectRecord.myProperty.delete()\n *\n * @param {object} filter\n *\n * @returns {object|array|string} result\n *\n * */\n function collectionFindOne(filter) {\n\n if ( typeof(filter) !== 'object' ) {\n throw new Error('filter must be an object');\n } else {\n var content = collections[ this['_collection'] ]\n , condition = filter.count()\n , i = 0\n , result = null\n , localeLowerCase = '';\n\n\n //console.log('condition ', condition, '\\nfitler', filter, '\\ncontent', content);\n if (condition == 0) return null;\n\n for (var o in content) {\n for (var f in filter) {\n localeLowerCase = ( typeof(filter[f]) != 'boolean' ) ? filter[f].toLocaleLowerCase() : filter[f];\n if ( filter[f] && keywords.indexOf(localeLowerCase) > -1 && localeLowerCase == 'not null' && typeof(content[o][f]) != 'undefined' && typeof(content[o][f]) !== 'object' && content[o][f] === filter[f] && content[o][f] != 'null' && content[o][f] != 'undefined' ) {\n if (result.indexOf(content[o][f]) < 0 ) {\n ++i;\n if (i === condition) {\n result = content[o];\n result['_index'] = o;\n result['_collection'] = this['_collection'];\n result['_bucket'] = this['_bucket'];\n }\n\n }\n\n } else if ( typeof(content[o][f]) != 'undefined' && typeof(content[o][f]) !== 'object' && content[o][f] === filter[f] ) {\n ++i;\n if (i === condition) {\n result = content[o];\n result['_index'] = o;\n result['_collection'] = this['_collection'];\n result['_bucket'] = this['_bucket'];\n result['_filter'] = filter;\n }\n }\n }\n }\n }\n\n if (result) {\n /**\n * save\n * e.g.:\n * // updating property\n * <obj>.property = 'value';\n * <obj>.save();\n *\n * // deleting property\n * delete <obj>.property;\n * <obj>.save(true);\n *\n * @param {boolean} enforceDeleted\n * */\n result['save'] = collectionSave\n }\n\n\n return result\n }\n\n /**\n * Delete from collection\n *\n * @param {object} filter\n *\n * @return {array} result\n * */\n function collectionDelete(filter) {\n\n if ( typeof(filter) !== 'object' ) {\n throw new Error('filter must be an object');\n } else {\n var content = JSON.clone( collections[ this['_collection'] ] )\n //, condition = filter.count()\n , i = 0\n , found = [];\n\n for (var o in content) {\n for (var f in filter) {\n if ( filter[f] && keywords.indexOf(filter[f].toLocaleLowerCase()) > -1 && filter[f].toLowerCase() == 'not null' && typeof(content[o][f]) != 'undefined' && typeof(content[o][f]) !== 'object' && content[o][f] != 'null' && content[o][f] != 'undefined' ) {\n if (found.indexOf(content[o][f]) < 0 ) {\n found[i] = content[o][f];\n delete collections[ this['_collection'] ][o][f];\n ++i\n }\n\n } else if ( typeof(content[o][f]) != 'undefined' && typeof(content[o][f]) !== 'object' && content[o][f] === filter[f] ) {\n found[i] = content[o];\n collections[ this['_collection'] ].splice(o, 1);\n ++i\n }\n }\n }\n }\n\n if (found.length > 0 ) {\n storage.setItem(this['_bucket'], JSON.stringify(collections));\n return true\n }\n\n return false\n }\n\n init(options);\n\n\n return bucketInstance\n};\n\nif ( ( typeof(module) !== 'undefined' ) && module.exports ) {\n // Publish as node.js module\n var merge = require('utils/merge');//require('../../../../../lib/merge');\n var Collection = require('utils/collection');//require('../../../../../lib/collection');\n var uuid = require('uuid');\n\n module.exports = StoragePlugin\n\n} else if ( typeof(define) === 'function' && define.amd) {\n // Publish as AMD module\n define('gina/storage', ['helpers/dateFormat', 'helpers/prototypes'],function() { return StoragePlugin })\n};\n",
43
43
  "/**\n * Operations on selectors\n * */\n\nfunction insertAfter(referenceNode, newNode) {\n referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling)\n}\n\nfunction getElementsByAttribute(attribute) {\n var matching = [], m = 0;\n var els = document.getElementsByTagName('*');\n\n for (var i = 0, n = els.length; i < n; ++i) {\n if (els[i].getAttribute(attribute) !== null) {\n // Element exists with attribute. Add to array.\n matching[m] = els[i];\n ++m\n }\n }\n\n return matching\n}\n\n/*\n * DOMParser HTML extension\n * 2012-09-04\n * \n * By Eli Grey, http://eligrey.com\n * Public domain.\n * \n * Added in gina on: 2020-12-12\n * \n */\n\n/*! @source https://gist.github.com/1129031 */\n/*global document, DOMParser*/\n(function(DOMParser) {\n\t\"use strict\";\n\n\tvar proto = DOMParser.prototype, \n nativeParse = proto.parseFromString;\n\n\t// Firefox/Opera/IE trigger errors for unsupported types\n\ttry {\n\t\t// WebKit returns null for unsupported types\n\t\tif ((new DOMParser()).parseFromString(\"\", \"text/html\")) {\n\t\t\t// text/html natvely supported\n\t\t\treturn;\n\t\t}\n\t} catch (ex) {}\n\n\tproto.parseFromString = function(markup, type) {\n\t\tif (/^\\s*text\\/html\\s*(?:;|$)/i.test(type)) {\n\t\t\tvar doc = document.implementation.createHTMLDocument(\"\");\n\t\t\t\n\t\t\tif (markup.toLowerCase().indexOf('<!doctype') > -1) {\n\t\t\t\tdoc.documentElement.innerHTML = markup;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdoc.body.innerHTML = markup;\n\t\t\t}\n\t\t\treturn doc;\n\t\t} else {\n\t\t\treturn nativeParse.apply(this, arguments);\n\t\t}\n\t};\n}(DOMParser));\ndefine(\"utils/dom\", function(){});\n\n",
44
44
  "/**\n * ValidatorPlugin\n *\n * Dependencies:\n * - utils/form-validator\n * - utils/merge\n * - utils/events\n * - vendor/uuid\n * \n * Additional helpers for the backend are located in framwework/v{version}/helpers/plugins/validator-*.js\n * \n * At Form Level \n * - data-gina-form-live-check-enabled\n * - data-gina-form-required-before-submit\n * \n * @param {object} rule\n * @param {object} [ data ] // from request\n * @param {string} [ formId ]\n * */\n function ValidatorPlugin(rules, data, formId) {\n\n this.plugin = 'validator';\n\n /**\n * validator event handler - isGFFCtx only\n * */\n var events = [\n 'init', // form or popin init\n 'ready',\n 'registered',\n 'success',\n 'error',\n 'progress',\n 'submit',\n 'reset',\n 'change',\n 'changed',\n 'keydown', // for autocomplete\n 'keyup', // for autocomplete\n 'focusout',\n 'focusin',\n 'validate', // for form livecheck (validation)\n 'validated', // for form livecheck (validation)\n 'destroy',\n 'asyncCompleted'\n ];\n \n // See: https://developer.mozilla.org/fr/docs/Web/HTML/Element/Input\n var allowedLiveInputTypes = [\n 'radio',\n 'checkbox',\n \n 'text',\n 'hidden',\n 'password',\n 'number', // not supporting float\n 'date',\n 'email',\n // extended types\n 'search',\n 'color',\n 'tel',\n 'range',\n 'time',\n 'datetime-local',\n 'datetime', // deprecated\n 'month',\n 'week',\n 'url'\n ];\n\n /** imports */\n var isGFFCtx = ( ( typeof(module) !== 'undefined' ) && module.exports ) ? false : true;\n if (isGFFCtx) {\n require('utils/events');\n registerEvents(this.plugin, events);\n\n require('utils/dom');\n require('utils/effects');\n\n } else {\n var cacheless = (process.env.IS_CACHELESS == 'false') ? false : true;\n if (cacheless) {\n delete require.cache[require.resolve('./form-validator')]\n }\n }\n\n var uuid = (isGFFCtx) ? require('vendor/uuid') : require('uuid');\n var merge = (isGFFCtx) ? require('utils/merge') : require('../../../../../lib/merge');\n var inherits = (isGFFCtx) ? require('utils/inherits') : require('../../../../../lib/inherits');\n var FormValidator = (isGFFCtx) ? require('utils/form-validator') : require('./form-validator');\n //var Collection = (isGFFCtx) ? require('utils/collection') : require('../../../../../lib/collection');\n var routing = (isGFFCtx) ? require('utils/routing') : require('../../../../../lib/routing');\n \n /** definitions */\n var instance = { \n 'id' : 'validator-' + uuid.v4(),\n\n 'plugin' : this.plugin,\n 'on' : (isGFFCtx) ? on : null,\n 'eventData' : {},\n 'target' : (isGFFCtx) ? document : null, // by default\n 'errors' : {},\n 'initialized' : false,\n 'isReady' : false,\n 'rules' : {},\n '$forms' : {},\n 'getFormById' : null,\n 'validateFormById' : null,\n 'setOptions' : null,\n 'resetErrorsDisplay': null,\n 'resetFields' : null\n };\n\n // validator proto\n var $validator = { // isGFFCtx only\n 'id' : null, // form id\n\n 'plugin' : this.plugin,\n 'on' : (isGFFCtx) ? on : null,\n 'eventData' : {},\n 'target' : (isGFFCtx) ? document : null, // by default\n 'cachedErrors' : {},\n 'binded' : false,\n 'unbinded' : false,\n 'withUserBindings' : false,\n 'rules' : {},\n 'setOptions' : null,\n 'send' : null,\n 'isValidating' : null,\n 'isSubmitting' : null,\n 'submit' : null,\n 'destroy' : null,\n 'resetErrorsDisplay' : null,\n 'resetFields' : null\n };\n \n var local = {\n rules: {}\n };\n \n var keyboardMapping = {};\n\n /**\n * XML Request - isGFFCtx only\n * */\n var xhr = null;\n var xhrOptions = {\n 'url' : '',\n 'method' : 'GET',\n 'isSynchrone' : false,\n 'withCredentials': false,\n 'headers' : {\n // to upload, use `multipart/form-data` for `enctype`\n 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',\n // cross domain is enabled by default, but you need to setup `Access-Control-Allow-Origin`\n 'X-Requested-With': 'XMLHttpRequest' // in case of cross domain origin\n\n }\n };\n\n /**\n * backend definitions\n * */\n var setCustomRules = function (customRules) {\n // parsing rules\n if ( typeof(customRule) != 'undefined' ) {\n try {\n parseRules(customRule, '');\n customRule = checkForRulesImports(customRule);\n } catch (err) {\n throw err\n }\n }\n }\n\n var backendProto = {\n 'setCustomRules': setCustomRules\n };\n\n\n /**\n * Backend init\n *\n * @param {object} rules\n * @param {object} [customRule]\n * */\n var backendInit = function (rules, data, formId) {\n\n var $form = ( typeof(formId) != 'undefined' ) ? { 'id': formId } : null;\n var fields = {};\n \n for (var field in data) {\n fields[field] = data[field]\n }\n\n\n // parsing rules\n if ( typeof(rules) != 'undefined' && rules.count() > 0 ) {\n \n try {\n parseRules(rules, '');\n rules = checkForRulesImports(rules);\n } catch (err) {\n throw err\n }\n \n backendProto.rules = instance.rules;\n\n return validate($form, fields, null, instance.rules)\n\n } else {\n // without rules - by hand\n return new FormValidator(fields)\n }\n }\n\n\n /**\n * GFF definitions\n * */\n var setOptions = function (options) {\n options = merge(options, xhrOptions);\n xhrOptions = options;\n }\n\n\n var getFormById = function(formId) {\n var $form = null, _id = formId;\n\n if ( !instance['$forms'] )\n throw new Error('`$forms` collection not found');\n\n if ( typeof(_id) == 'undefined') {\n throw new Error('[ FormValidator::getFormById(formId) ] `formId` is missing')\n }\n\n _id = _id.replace(/\\#/, ''); \n \n // in case form is created on the fly and is not yet registered\n if (document.getElementById(_id) != null && typeof (instance['$forms'][_id]) == 'undefined') {\n initForm( document.getElementById(_id) );\n } \n \n if ( typeof(instance.$forms[_id]) != 'undefined' ) { \n instance['$forms'][_id].withUserBindings = true;\n if ( typeof(this.$forms[_id]) == 'undefined') { \n $form = this.$forms[_id] = instance['$forms'][_id];\n } else {\n $form = instance.$forms[_id];\n } \n } \n \n if (!$form) {\n throw new Error('Validator::getFormById(...) exception: could not retrieve form `'+ _id +'`');\n }\n \n if ( !$form.binded) {\n var $target = $form.target;\n bindForm($target);\n $form = instance.$forms[_id];\n }\n \n \n \n // update toolbar\n if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) {\n // update toolbar\n if (!gina.forms.errors)\n gina.forms.errors = {};\n\n var objCallback = {\n id : _id,\n rules : instance.$forms[_id].rules\n };\n if ( typeof(instance.$forms[_id].errors) != 'undefined' ) {\n objCallback.errors = instance.$forms[_id].errors\n }\n\n window.ginaToolbar.update('forms', objCallback);\n }\n\n return $form;\n }\n \n /**\n * isPopinContext\n * \n * @return {boolean} isPopinContext\n */\n var isPopinContext = function() {\n var isPopinInUse = false, $activePopin = null;\n \n if ( gina.hasPopinHandler && gina.popinIsBinded ) {\n $activePopin = gina.popin.getActivePopin();\n }\n \n if ( $activePopin && $activePopin.isOpen ) {\n isPopinInUse = true;\n }\n \n return isPopinInUse;\n }\n\n\n /**\n * validateFormById\n *\n * @param {string} formId\n * @param {object} [customRule]\n *\n * @return {object} $form\n * */\n var validateFormById = function(formId, customRule) {\n var $form = null\n , _id = formId\n , rules = ( typeof(local.rules.count() > 0 ) ) ? local.rules : instance.rules\n , $target = null\n ;\n \n if ( !instance['$forms'] ) {\n throw new Error('`$forms` collection not found')\n }\n // Return existing when available\n if ( typeof(_id) != 'undefined' && typeof(instance.$forms[_id]) != 'undefined' ) {\n return instance.$forms[_id];\n }\n\n if ( typeof(_id) == 'undefined' ) {\n if ( typeof(this.id) != 'undefined' && this.id != '' && this.id != null ) {\n _id = this.id\n } else {\n throw new Error('[ FormValidator::validateFormById(formId, customRule) ] `formId` is missing')\n }\n }\n\n if ( typeof(_id) == 'string') {\n _id = _id.replace(/\\#/, '')\n } else if ( typeof(_id) == 'object' && !Array.isArray(_id) ) { // weird exception\n\n $target = _id.form;\n _id = $target.getAttribute('id') || 'form.'+uuid.v4();\n\n $target.setAttribute('id', _id);// just in case\n\n } else {\n throw new Error('[ FormValidator::validateFormById(formId[, customRule]) ] `formId` should be a `string`');\n }\n\n checkForDuplicateForm(_id);\n \n if ( typeof(instance['$forms'][_id]) != 'undefined' ) { \n $form = this.$forms[_id] = instance['$forms'][_id];\n } else { // binding a form out of context (outside of the main instance)\n $target = document.getElementById(_id);\n $validator.id = _id;\n $validator.target = $target;\n\n $form = this.$forms[_id] = instance.$forms[_id] = merge({}, $validator);\n\n var rule = null;\n if ( typeof(customRule) == 'undefined') {\n rule = _id.replace(/\\-/g, '.');\n\n if ( typeof(rules) != 'undefined' ) {\n $form['rule'] = customRule = getRuleObjByName(rule)\n } else if ( typeof($form.target) != 'undefined' && $form.target !== null && $form.target.getAttribute('data-gina-form-rule') ) {\n rule = $form.target.getAttribute('data-gina-form-rule').replace(/\\-|\\//g, '.');\n\n if ( typeof(rules) != 'undefined' ) {\n $form['rule'] = getRuleObjByName(rule)\n } else {\n throw new Error('[ FormValidator::validateFormById(formId) ] using `data-gina-form-rule` on form `'+$form.target+'`: no matching rule found')\n }\n } // no else to allow form without any rule\n } else {\n rule = customRule.replace(/\\-|\\//g, '.');\n\n if ( typeof(rules) != 'undefined' ) {\n $form['rule'] = getRuleObjByName(rule)\n } else {\n throw new Error('[ FormValidator::validateFormById(formId, customRule) ] `'+customRule+'` is not a valid rule')\n }\n }\n \n if ( $target && typeof(this.isPopinContext) != 'undefined' && /true/i.test(this.isPopinContext) ) {\n $target.isPopinContext = this.isPopinContext;\n }\n \n if ($target && !$form.binded)\n bindForm($target, rule);\n }\n \n \n\n if (!$form) throw new Error('[ FormValidator::validateFormById(formId, customRule) ] `'+_id+'` not found');\n\n return $form || null;\n\n }\n \n var refreshWarning = function($el) {\n var formId = $el.form.getAttribute('id');\n if ( /^true$/i.test(instance.$forms[formId].isValidating) ) {\n return;\n }\n \n var $parent = $el.parentNode, isErrorMessageHidden = false;\n var $children = $parent.getElementsByTagName('div');\n \n if ( /form\\-item\\-warning/.test($parent.className) ) {\n $parent.className = $parent.className.replace(/form\\-item\\-warning/, 'form-item-error');\n \n } else if (/form\\-item\\-error/.test($parent.className) ) { \n $parent.className = $parent.className.replace(/form\\-item\\-error/, 'form-item-warning');\n isErrorMessageHidden = true;\n }\n \n\n for (var c = 0, cLen = $children.length; c<cLen; ++c) {\n if ( /form\\-item\\-error\\-message/.test($children[c].className) ) {\n if (isErrorMessageHidden) {\n // hide error messages\n $children[c].className = $children[c].className +' hidden';\n } else {\n // display error messages\n $children[c].className = $children[c].className.replace(/(\\s+hidden|hidden)/, '');\n }\n break\n }\n }\n }\n\n /**\n * handleErrorsDisplay\n * Attention: if you are going to handle errors display by hand, set data to `null` to prevent Toolbar refresh with empty data\n * @param {object} $form - Target (HTMLFormElement)\n * @param {object} errors \n * @param {object|null} data\n * @param {object|null} [fileName]\n */\n var liveCheckErrors = {}; // Per Form & Per Element\n var handleErrorsDisplay = function($form, errors, data, fieldName) {\n \n // Toolbar errors display\n if ( GINA_ENV_IS_DEV )\n var formsErrors = null;\n \n var errorClass = 'form-item-error' // by default\n , isWarning = false\n ; \n // catch reset\n if ( \n typeof($form.dataset.ginaFormIsResetting) != 'undefined' \n && /^(true)$/i.test($form.dataset.ginaFormIsResetting) \n ) {\n errors = {};\n liveCheckErrors = {};\n // restore default\n $form.dataset.ginaFormIsResetting = false;\n } else {\n // Live check enabled ?\n if ( \n /^(true)$/i.test($form.dataset.ginaFormLiveCheckEnabled) \n && typeof(fieldName) != 'undefined'\n ) {\n var formId = ( typeof($form.id) != 'string' ) ? $form.getAttribute('id') : $form.id;\n if ( typeof(liveCheckErrors[formId]) == 'undefined') {\n liveCheckErrors[formId] = {};\n } \n if (errors.count() > 0) {\n // reset field name\n liveCheckErrors[formId][fieldName] = {};\n // override\n liveCheckErrors[formId][fieldName] = merge(errors[fieldName], liveCheckErrors[formId][fieldName]);\n if (liveCheckErrors[formId][fieldName].count() == 0) {\n delete liveCheckErrors[formId][fieldName]\n }\n errors = liveCheckErrors[formId];\n // only if the form has not been sent yet\n if (!instance.$forms[formId].sent || instance.$forms[formId].isValidating) {\n isWarning = true;\n }\n } else {\n if ( typeof(liveCheckErrors[formId][fieldName]) != 'undefined') {\n delete liveCheckErrors[formId][fieldName];\n if ( \n typeof(window.gina.validator.$forms[formId].errors) != 'undefined'\n && typeof(window.gina.validator.$forms[formId].errors[fieldName]) != 'undefined'\n ) {\n delete window.gina.validator.$forms[formId].errors[fieldName];\n }\n }\n if ( \n typeof(instance.$forms) != 'undefined'\n && typeof(instance.$forms[formId]) != 'undefined' \n && typeof(instance.$forms[formId].errors) != 'undefined' \n && instance.$forms[formId].errors.count() == 0 \n ) {\n // update submit trigger state\n updateSubmitTriggerState( $form, true );\n }\n \n if ( typeof(liveCheckErrors[formId]) != 'undefined' && liveCheckErrors[formId].count() == 0 ) {\n delete liveCheckErrors[formId]\n } else {\n errors = liveCheckErrors[formId];\n }\n \n \n }\n }\n }\n \n \n var name = null, errAttr = null;\n var $err = null, $msg = null;\n var $el = null, $parent = null, $target = null;\n var id = $form.getAttribute('id');\n // TODO - Refacto on this may be done later since we are doing nothing with it\n data = ( typeof(data) != 'undefined' ) ? data : {};\n\n for (var i = 0, len = $form.length; i<len; ++i) {\n \n $el = $form[i];\n \n if (typeof(fieldName) != 'undefined' && fieldName != $el.name) continue;\n \n if ( /form\\-item\\-wrapper$/.test($el.parentNode.className) ) {\n $parent = $el.parentNode.parentNode;\n $target = $el.parentNode;\n } else {\n $parent = $el.parentNode;\n $target = $el;\n }\n\n name = $el.getAttribute('name');\n errAttr = $el.getAttribute('data-gina-form-errors');\n\n if (!name) continue;\n\n if ( typeof(errors[name]) != 'undefined' && !/(form\\-item\\-error|form\\-item\\-warning)/.test($parent.className) ) {\n \n if (isWarning) {\n // adding warning class\n $parent.className += ($parent.className == '' ) ? 'form-item-warning' : ' form-item-warning';\n } else {\n //$parent.className = $parent.className.replace(/(\\s+form\\-item\\-warning|form\\-item\\-warning)/, '');\n $parent.className += ($parent.className == '' ) ? 'form-item-error' : ' form-item-error';\n }\n $err = document.createElement('div');\n if (isWarning) {\n //$err.setAttribute('class', 'form-item-error-message hidden');\n $err.className = 'form-item-error-message hidden';\n } else {\n //$err.setAttribute('class', 'form-item-error-message');\n $err.className = 'form-item-error-message';\n }\n \n // injecting error messages\n for (var e in errors[name]) {\n\n if (e != 'stack') { // ignore stack for display\n $msg = document.createElement('p');\n $msg.appendChild( document.createTextNode(errors[name][e]) );\n $err.appendChild($msg);\n }\n\n if ( GINA_ENV_IS_DEV ) {\n if (!formsErrors) formsErrors = {};\n if ( !formsErrors[ name ] )\n formsErrors[ name ] = {};\n \n formsErrors[ name ][e] = errors[name][e]\n }\n }\n \n if ($target.type != 'hidden')\n insertAfter($target, $err);\n\n \n\n } else if ( typeof(errors[name]) == 'undefined' && /(form\\-item\\-error|form\\-item\\-warning)/.test($parent.className) || typeof(errors[name]) != 'undefined' && errors[name].count() == 0 && /(form\\-item\\-error|form\\-item\\-warning)/.test($parent.className) ) {\n // reset when not in error\n // remove child elements\n var $children = $parent.getElementsByTagName('div');\n for (var c = 0, cLen = $children.length; c<cLen; ++c) {\n if ( /form\\-item\\-error\\-message/.test($children[c].className) ) {\n $children[c].parentElement.removeChild($children[c]);\n break\n }\n \n }\n\n $parent.className = $parent.className.replace(/(\\s+form\\-item\\-error|form\\-item\\-error|\\s+form\\-item\\-warning|form\\-item\\-warning)/, '');\n\n } else if ( typeof(errors[name]) != 'undefined' && errAttr) {\n // refreshing already displayed error on msg update\n var $divs = $parent.getElementsByTagName('div');\n for (var d = 0, dLen = $divs.length; d<dLen; ++d) {\n if ($divs[d].className == 'form-item-error-message') {\n\n $divs[d].parentElement.removeChild($divs[d]);\n $err = document.createElement('div');\n $err.setAttribute('class', 'form-item-error-message');\n\n // injecting error messages\n // {\n // field: {\n // rule: errorMsg\n // }\n // }\n for (var e in errors[name]) {\n $msg = document.createElement('p');\n $msg.appendChild( document.createTextNode(errors[name][e]) );\n $err.appendChild($msg);\n\n if ( GINA_ENV_IS_DEV ) {\n if (!formsErrors) formsErrors = {};\n if ( !formsErrors[ name ] )\n formsErrors[ name ] = {};\n\n formsErrors[ name ][e] = errors[name][e]\n }\n }\n\n break;\n }\n }\n\n if ($err && $target.type != 'hidden')\n insertAfter($target, $err);\n\n }\n \n if (typeof(fieldName) != 'undefined' && fieldName === $el.name) break;\n }\n\n\n var objCallback = null;\n if ( formsErrors ) {\n\n triggerEvent(gina, $form, 'error.' + id, errors)\n\n if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) {\n // update toolbar\n if (!gina.forms.errors)\n gina.forms.errors = {};\n\n objCallback = {\n id : id,\n errors : formsErrors\n };\n\n window.ginaToolbar.update('forms', objCallback);\n }\n } else if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar) { // reset toolbar form errors\n if (!gina.forms.errors)\n gina.forms.errors = {};\n\n objCallback = {\n id: id,\n errors: {}\n };\n if (isGFFCtx)\n window.ginaToolbar.update('forms', objCallback);\n }\n\n if (\n gina \n && isGFFCtx \n && GINA_ENV_IS_DEV\n && instance.$forms[id].isSubmitting\n && /^true$/i.test(instance.$forms[id].isSubmitting) \n && typeof(window.ginaToolbar) != 'undefined' \n && window.ginaToolbar \n && data\n ) {\n \n try {\n // update toolbar\n window.ginaToolbar.update('data-xhr', data);\n\n } catch (err) {\n throw err\n }\n }\n\n }\n\n\n /**\n * Reset errors display\n *\n * @param {object|string} $formOrFormId [$formInstance|$formInstance.target|$formInstance.id]\n *\n * */\n var resetErrorsDisplay = function($formOrFormId) {\n var _id = null, $form = null;\n if ( typeof($formOrFormId) == 'undefined' && typeof(this.id) != 'undefined' ) {\n $formOrFormId = this.id;\n }\n if ( /^string$/i.test(typeof($formOrFormId)) ) {\n _id = $formOrFormId.replace(/\\#/, '');\n $form = document.getElementById(_id);\n } else if ( $formOrFormId instanceof HTMLFormElement ) {\n $form = $formOrFormId\n } else if ( /^object$/i.test(typeof($formOrFormId)) ) {\n $form = $formOrFormId.target;\n }\n \n if (!$form) {\n throw new Error('[ FormValidator::resetErrorsDisplay([ formId | <form> ]) ] `'+$formOrFormId+'` not found')\n }\n \n // Resetting error display\n $form.dataset.ginaFormIsResetting = true;\n handleErrorsDisplay($form, {});\n \n\n return $form\n }\n\n /**\n * Reset fields\n *\n * @param {object|string} [$form|formId]\n *\n * */\n var resetFields = function($form) {\n var _id = null;\n if ( typeof($form) == 'undefined' ) {\n if ( typeof(this.target) != 'undefined' ) {\n _id = this.target.getAttribute('id');\n } else {\n _id = this.getAttribute('id');\n }\n\n $form = instance.$forms[_id]\n } else if ( typeof($form) == 'string' ) {\n _id = $form;\n _id = _id.replace(/\\#/, '');\n\n if ( typeof(instance.$forms[_id]) == 'undefined') {\n throw new Error('[ FormValidator::resetErrorsDisplay([formId]) ] `'+$form+'` not found')\n }\n\n $form = instance.$forms[_id]\n }\n\n if ($form.fieldsSet) {\n\n var elId = null\n , $element = null\n , tagName = null\n , type = null\n , value = null // current value\n , defaultValue = null\n ;\n\n for (var f in $form.fieldsSet) {\n\n $element = document.getElementById(f);\n type = $element.tagName.toLowerCase();\n tagName = $element.tagName;\n \n if ( /textarea/i.test(tagName) ) {\n defaultValue = $form.fieldsSet[f].defaultValue;\n $element.value = defaultValue;\n triggerEvent(gina, $element, 'change');\n continue;\n }\n\n if (type == 'input') {\n \n defaultValue = $form.fieldsSet[f].defaultValue;\n \n if (/$(on|true|false)$/i.test(defaultValue)) {\n defaultValue = (/$(on|true)$/i.test(defaultValue)) ? true : false;\n }\n \n if ( /^(checkbox|radio)$/i.test($element.type) ) {\n $element.checked = $form.fieldsSet[f].defaultChecked;\n } else if ( !/^(checkbox|radio)$/i.test($element.type) ) {\n $element.value = defaultValue;\n }\n triggerEvent(gina, $element, 'change');\n \n } else if ( type == 'select' ) {\n defaultValue = $form.fieldsSet[f].selectedIndex || 0;\n $element.selectedIndex = defaultValue;\n $element.dataset.value = $element.options[ $element.selectedIndex ].value;\n triggerEvent(gina, $element, 'change');\n }\n \n }\n }\n\n return $form\n }\n\n var submit = function () {\n\n var $form = null, _id = null, $target = null;\n\n if ( typeof(this.getAttribute) != 'undefined' ) {\n _id = this.getAttribute('id');\n $target = this;\n } else if ( typeof(this.target) != 'undefined' && this.target != null && typeof(this.target.getAttribute) != 'undefined' ) {\n _id = this.target.getAttribute('id');\n $target = this.target\n }\n\n if ( typeof(instance.$forms[_id]) == 'undefined') {\n throw new Error('[ FormValidator::submit() ] not `$form` binded. Use `FormValidator::getFormById(id)` or `FormValidator::validateFormById(id)` first ')\n }\n\n triggerEvent(gina, $target, 'submit');\n\n return this;\n }\n \n \n\n /**\n * send\n * N.B.: no validation here; if you want to validate against rules, use `.submit()` before\n *\n *\n * @param {object} data\n * @param {object} [ options ] : { isSynchrone: true, withCredentials: true }\n * */\n var send = function(data, options) {\n \n \n var $target = this.target , id = $target.getAttribute('id');\n var $form = instance.$forms[id] || this;\n var result = null;\n var XHRData = null;\n var isAttachment = null; // handle download\n var hFormIsRequired = null;\n \n if ( \n typeof($form.isSending) != 'undefined'\n && /^true$/i.test($form.isSending)\n ||\n typeof($form.sent) != 'undefined'\n && /^true$/i.test($form.sent)\n ) {\n return;\n }\n instance.$forms[id].isSending = true;\n \n \n options = (typeof (options) != 'undefined') ? merge(options, xhrOptions) : xhrOptions;\n // `x-gina-form`definition\n //options.headers['X-Gina-Form-Location'] = gina.config.bundle;\n if ( typeof($form.id) != 'undefined' ) {\n options.headers['X-Gina-Form-Id'] = $form.id;\n if ( \n typeof(gina.forms.rules) != 'undefined' \n && $form.rules.count() > 0\n && typeof($form.rules[$form.id]) != 'undefined'\n ) {\n options.headers['X-Gina-Form-Rule'] = $form.id +'@'+ gina.config.bundle;\n } \n }\n // if ( typeof($form.name) != 'undefined' ) {\n // options.headers['X-Gina-Form-Name'] = $form.name;\n // } \n if ( typeof($form.target.dataset.ginaFormRule) != 'undefined' ) {\n options.headers['X-Gina-Form-Rule'] = $form.target.dataset.ginaFormRule +'@'+ gina.config.bundle;\n } \n \n \n // forward callback to HTML data event attribute through `hform` status\n hFormIsRequired = ( $target.getAttribute('data-gina-form-event-on-submit-success') || $target.getAttribute('data-gina-form-event-on-submit-error') ) ? true : false;\n // success -> data-gina-form-event-on-submit-success\n // error -> data-gina-form-event-on-submit-error\n if (hFormIsRequired)\n listenToXhrEvents($form);\n\n var url = $target.getAttribute('action') || options.url;\n var method = $target.getAttribute('method') || options.method;\n method = method.toUpperCase();\n options.method = method;\n options.url = url;\n \n if (!xhr) {\n xhr = setupXhr(options);\n }\n\n // to upload, use `multipart/form-data` for `enctype`\n var enctype = $target.getAttribute('enctype') || options.headers['Content-Type'];\n \n\n if ( options.withCredentials ) {\n\n if ('withCredentials' in xhr) {\n // XHR for Chrome/Firefox/Opera/Safari.\n if (options.isSynchrone) {\n xhr.open(options.method, options.url, options.isSynchrone)\n } else {\n xhr.open(options.method, options.url)\n }\n } else if ( typeof XDomainRequest != 'undefined' ) {\n // XDomainRequest for IE.\n xhr = new XDomainRequest();\n xhr.open(options.method, options.url);\n } else {\n // CORS not supported.\n xhr = null;\n result = 'CORS not supported: the server is missing the header `\"Access-Control-Allow-Credentials\": true` ';\n triggerEvent(gina, $target, 'error.' + id, result);\n\n return\n }\n \n if ( typeof(options.responseType) != 'undefined' ) {\n xhr.responseType = options.responseType;\n } else {\n xhr.responseType = '';\n }\n\n xhr.withCredentials = true;\n } else {\n if (options.isSynchrone) {\n xhr.open(options.method, options.url, options.isSynchrone)\n } else {\n xhr.open(options.method, options.url)\n }\n }\n\n // setting up headers - all but Content-Type ; it will be set right before .send() is called\n for (var hearder in options.headers) {\n //if ( hearder == 'Content-Type' && typeof (enctype) != 'undefined' && enctype != null && enctype != '') {\n // options.headers[hearder] = enctype\n //}\n if (hearder == 'Content-Type' && typeof (enctype) != 'undefined' && enctype != null && enctype != '')\n continue;\n\n xhr.setRequestHeader(hearder, options.headers[hearder]);\n }\n \n if (xhr) {\n // catching ready state cb\n //handleXhrResponse(xhr, $target, id, $form, hFormIsRequired);\n xhr.onreadystatechange = function onValidationCallback(event) {\n $form.isSubmitting = false;\n $form.isSending = false;\n \n // limit send trigger to 1 sec to prevent from double clicks\n setTimeout( function onSent() {\n $form.sent = false;\n }, 1000);\n \n // In case the user is also redirecting\n var redirectDelay = (/Google Inc/i.test(navigator.vendor)) ? 50 : 0;\n \n if (xhr.readyState == 2) { // responseType interception\n isAttachment = ( /^attachment\\;/.test( xhr.getResponseHeader(\"Content-Disposition\") ) ) ? true : false; \n // force blob response type\n if ( !xhr.responseType && isAttachment ) {\n xhr.responseType = 'blob';\n }\n }\n\n if (xhr.readyState == 4) {\n var blob = null;\n var contentType = xhr.getResponseHeader(\"Content-Type\"); \n \n // 200, 201, 201' etc ...\n if( /^2/.test(xhr.status) ) {\n\n try { \n \n // handling blob xhr download\n if ( /blob/.test(xhr.responseType) || isAttachment ) {\n if ( typeof(contentType) == 'undefined' || contentType == null) {\n contentType = 'application/octet-stream';\n }\n \n blob = new Blob([this.response], { type: contentType });\n \n //Create a link element, hide it, direct it towards the blob, and then 'click' it programatically\n var a = document.createElement('a');\n a.style = \"display: none\";\n document.body.appendChild(a);\n //Create a DOMString representing the blob and point the link element towards it\n var url = window.URL.createObjectURL(blob);\n a.href = url;\n var contentDisposition = xhr.getResponseHeader(\"Content-Disposition\");\n a.download = contentDisposition.match('\\=(.*)')[0].substr(1);\n //programatically click the link to trigger the download\n a.click();\n //release the reference to the file by revoking the Object URL\n window.URL.revokeObjectURL(url);\n \n result = {\n status : xhr.status,\n statusText: xhr.statusText,\n responseType: blob.type,\n type : blob.type,\n size : blob.size \n }\n \n } else { // normal case\n result = xhr.responseText; \n }\n \n\n \n if ( /\\/json/.test( contentType ) ) {\n result = JSON.parse(xhr.responseText);\n \n if ( typeof(result.status) == 'undefined' )\n result.status = xhr.status;\n \n }\n \n if ( /\\/html/.test( contentType ) ) {\n \n result = {\n contentType : contentType,\n content : xhr.responseText\n };\n \n if ( typeof(result.status) == 'undefined' )\n result.status = xhr.status;\n \n // if hasPopinHandler & popinIsBinded\n if ( typeof(gina.popin) != 'undefined' && gina.hasPopinHandler ) { \n // select popin current active popin\n var $popin = gina.popin.getActivePopin();\n \n if ($popin) {\n \n XHRData = {};\n // update toolbar\n \n try {\n XHRData = new DOMParser().parseFromString(result.content, 'text/html').getElementById('gina-without-layout-xhr-data');\n XHRData = JSON.parse(decodeURIComponent(XHRData.value));\n \n XHRView = new DOMParser().parseFromString(result.content, 'text/html').getElementById('gina-without-layout-xhr-view'); \n XHRView = JSON.parse(decodeURIComponent(XHRView.value));\n \n // update data tab \n if ( gina && GINA_ENV_IS_DEV && typeof(window.ginaToolbar) && typeof(XHRData) != 'undefined' ) {\n window.ginaToolbar.update(\"data-xhr\", XHRData);\n }\n \n // update view tab\n \n if ( gina && GINA_ENV_IS_DEV && typeof(window.ginaToolbar) && typeof(XHRView) != 'undefined' ) {\n window.ginaToolbar.update(\"view-xhr\", XHRView);\n } \n\n } catch (err) {\n throw err\n }\n \n \n $popin.loadContent(result.content);\n \n result = XHRData;\n triggerEvent(gina, $target, 'success.' + id, result);\n \n return;\n }\n }\n }\n \n $form.eventData.success = result;\n\n XHRData = result;\n // update toolbar\n if ( gina && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar && XHRData ) {\n try {\n // don't refresh for html datas\n if ( GINA_ENV_IS_DEV && typeof(XHRData) != 'undefined' && /\\/html|\\/json/.test(contentType) ) {\n window.ginaToolbar.update(\"data-xhr\", XHRData);\n }\n\n } catch (err) {\n throw err\n }\n }\n\n // intercepts upload\n if ( /^gina\\-upload/i.test(id) )\n onUpload(gina, $target, 'success', id, result);\n \n // intercepts result.popin & popin redirect (from SuperController::redirect() )\n var isXhrRedirect = false;\n if (\n typeof(result.isXhrRedirect) != 'undefined'\n && /^true$/i.test(result.isXhrRedirect)\n ) {\n isXhrRedirect = true;\n }\n if ( \n typeof(gina.popin) != 'undefined'\n && gina.hasPopinHandler\n && typeof(result.popin) != 'undefined'\n ||\n typeof(gina.popin) != 'undefined'\n && gina.hasPopinHandler\n && typeof(result.location) != 'undefined'\n && isXhrRedirect\n ) {\n var $popin = gina.popin.getActivePopin();\n if ( !$popin && typeof(result.popin) != 'undefined' ) {\n if ( typeof(result.popin) != 'undefined' && typeof(result.popin.name) == 'undefined' ) {\n throw new Error('To get a `$popin` instance, you need at list a `popin.name`.');\n }\n $popin = gina.popin.getPopinByName(result.popin.name);\n if ( !$popin ) {\n throw new Error('Popin with name: `'+ result.popin.name +'` not found.')\n }\n }\n \n if ( \n typeof(result.popin) != 'undefined' \n && typeof(result.popin.close) != 'undefined'\n ) {\n $popin.isRedirecting = false;\n $popin.close();\n var _reload = (result.popin.reload) ? result.popin.reload : false;\n if ( !result.popin.location && !result.popin.url) {\n delete result.popin;\n // only exception\n if (_reload) {\n result.popin = { reload: _reload };\n }\n }\n }\n \n if ( \n typeof(result.popin) != 'undefined'\n && typeof(result.popin.location) != 'undefined'\n ||\n typeof(result.popin) != 'undefined'\n && typeof(result.popin.url) != 'undefined'\n ||\n typeof(result.location) != 'undefined'\n && isXhrRedirect\n ) { \n var popinName = null;\n if ( $popin ) {\n popinName = $popin.name; // by default\n $popin.isRedirecting = true;\n }\n \n var _target = '_self'; // by default\n if ( typeof(result.popin) != 'undefined' && typeof(result.popin.target) != 'undefined' ) {\n if ( /^(blank|self|parent|top)$/ ) {\n result.popin.target = '_'+result.popin.target;\n }\n _target = result.popin.target\n } \n \n //var popinUrl = (typeof(result.popin) != 'undefined') ? result.popin.location : result.location;\n var popinUrl = result.location || result.popin.location || result.popin.url;\n if ( \n typeof(result.popin) != 'undefined'\n && typeof(result.popin.name) != 'undefined'\n && popinName != result.popin.name\n ) {\n //$popin = gina.popin.getActivePopin();\n if ($popin)\n $popin.close();\n \n popinName = result.popin.name;\n $popin = gina.popin.getPopinByName(popinName);\n if ( !$popin ) {\n throw new Error('Popin with name `'+ popinName+'` not found !');\n }\n $popin.load($popin.name, popinUrl, $popin.options);\n } else if ($popin) {\n $popin.load($popin.name, popinUrl, $popin.options);\n }\n if ($popin) {\n return setTimeout( function onPopinredirect($popin){\n if (!$popin.isOpen) {\n $popin.open();\n return;\n }\n }, 50, $popin);\n } \n }\n }\n \n triggerEvent(gina, $target, 'success.' + id, result); \n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'success.' + id + '.hform', result);\n \n } catch (err) {\n\n result = {\n status: 422,\n error : err.message,\n stack : err.stack\n\n };\n\n $form.eventData.error = result;\n \n\n XHRData = result; \n // update toolbar\n if ( gina && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar && XHRData ) {\n try {\n\n if ( GINA_ENV_IS_DEV && typeof(XHRData) != 'undefined' ) {\n window.ginaToolbar.update(\"data-xhr\", XHRData);\n }\n\n } catch (err) {\n throw err\n }\n }\n \n // intercept upload\n if ( /^gina\\-upload/i.test(id) )\n onUpload(gina, $target, 'error', id, result);\n \n triggerEvent(gina, $target, 'error.' + id, result);\n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', result);\n }\n \n // handle redirect\n if ( typeof(result) != 'undefined' && typeof(result.location) != 'undefined' ) { \n window.location.hash = ''; //removing hashtag \n \n // if ( window.location.host == gina.config.hostname && /^(http|https)\\:\\/\\//.test(result.location) ) { // same origin\n // result.location = result.location.replace( new RegExp(gina.config.hostname), '' );\n // } else { // external - need to remove `X-Requested-With` from `options.headers`\n result.location = (!/^http/.test(result.location) && !/^\\//.test(result.location) ) ? location.protocol +'//' + result.location : result.location;\n //} \n \n return setTimeout(() => {\n window.location.href = result.location;\n }, redirectDelay); \n }\n\n } else if ( xhr.status != 0) {\n // XHR Error\n result = { 'status': xhr.status };\n // handling blob xhr error\n if ( /blob/.test(xhr.responseType) ) {\n \n blob = new Blob([this.response], { type: 'text/plain' });\n \n var reader = new FileReader(), blobError = '';\n \n \n // This fires after the blob has been read/loaded.\n reader.addEventListener('loadend', (e) => {\n \n if ( /string/i.test(typeof(e.srcElement.result)) ) {\n blobError += e.srcElement.result;\n // try {\n // result = merge( result, JSON.parse(blobError) )\n // } catch (err) {\n // result = merge(result, err)\n // }\n \n } else if ( typeof(e.srcElement.result) == 'object' ) {\n result = merge(result, e.srcElement.result)\n } else {\n result.message += e.srcElement.result\n }\n \n // once ready\n if ( /2/.test(reader.readyState) ) {\n \n if ( /^(\\{|\\[)/.test( blobError ) ) {\n try {\n result = merge( result, JSON.parse(blobError) )\n } catch(err) {\n result = merge(result, err)\n } \n }\n \n if (!result.message)\n delete result.message;\n // forward appplication errors to validator when available\n $form.eventData.error = result;\n\n // update toolbar\n XHRData = result;\n if ( gina && GINA_ENV_IS_DEV && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar && XHRData ) {\n try {\n // update toolbar\n window.ginaToolbar.update('data-xhr', XHRData );\n\n } catch (err) {\n throw err\n }\n }\n \n // intercept upload\n if ( /^gina\\-upload/i.test(id) )\n onUpload(gina, $target, 'error', id, result);\n \n triggerEvent(gina, $target, 'error.' + id, result); \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', result);\n \n return;\n }\n \n \n });\n\n // Start reading the blob as text.\n reader.readAsText(blob);\n \n } else { // normal case\n \n if ( /^(\\{|\\[)/.test( xhr.responseText ) ) {\n\n try {\n result = merge( JSON.parse(xhr.responseText), result )\n } catch (err) {\n result = merge(err, result)\n }\n\n } else if ( typeof(xhr.responseText) == 'object' ) {\n result = merge(xhr.responseText, result)\n } else {\n result.message = xhr.responseText\n }\n \n // xhr error response (caching)\n //$form.eventData.error = result;\n // Forward appplication errors to forms.errors when available\n // This api error is meant for the Frontend Validation Errors Handling\n if ( typeof(result) != 'undefined' && typeof(result.error) != 'undefined' && result.fields && typeof(result.fields) == 'object') {\n \n var apiMessage = ( typeof(result.message) != 'undefined') ? result.message : null;\n var newResultfields = {};\n for (let f in result.fields) {\n let errorObject = {};\n errorObject[f] = {};\n errorObject[f].isApiError = result.fields[f];\n if ( apiMessage && !errorObject[f].isApiError) {\n errorObject[f].isApiError = result.error; // Generic error\n }\n newResultfields[f] = errorObject[f];\n handleErrorsDisplay($form.target, errorObject, data, f);\n \n }\n result.fields = newResultfields\n } \n $form.eventData.error = result;\n \n\n // update toolbar\n XHRData = result;\n if ( gina && GINA_ENV_IS_DEV && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar && XHRData ) {\n try {\n // update toolbar\n window.ginaToolbar.update('data-xhr', XHRData );\n\n } catch (err) {\n throw err\n }\n }\n \n\n // intercept upload\n if ( /^gina\\-upload/i.test(id) )\n onUpload(gina, $target, 'error', id, result);\n \n triggerEvent(gina, $target, 'error.' + id, result); \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', result);\n \n \n \n }\n\n \n } /**else if ( xhr.readyState == 4 && xhr.status == 0 ) { // unknown error\n // Consider also the request timeout\n // Modern browser return readyState=4 and status=0 if too much time passes before the server response.\n result = { 'status': 408, 'message': 'XMLHttpRequest Exception: unkown error' };\n XHRData = result;\n // update toolbar\n if ( gina && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar && XHRData ) {\n try {\n // don't refresh for html datas\n if ( GINA_ENV_IS_DEV && typeof(XHRData) != 'undefined' && /\\/html/.test(contentType) ) {\n window.ginaToolbar.update(\"data-xhr\", XHRData);\n }\n\n } catch (err) {\n throw err\n }\n }\n \n // intercept upload\n if ( /^gina\\-upload/i.test(id) ) {\n result.message = 'XMLHttpRequest Exception: trying to render an unknwon file.'\n onUpload(gina, $target, 'error', id, result);\n }\n triggerEvent(gina, $target, 'error.' + id, result);\n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', result);\n \n return;\n }*/\n } \n \n };\n\n // catching request progress\n xhr.onprogress = function(event) {\n \n var percentComplete = '0';\n if (event.lengthComputable) {\n percentComplete = event.loaded / event.total;\n percentComplete = parseInt(percentComplete * 100);\n\n }\n\n //var percentComplete = (event.position / event.totalSize)*100;\n var result = {\n 'status': 100,\n 'progress': percentComplete\n };\n \n //console.debug('xhr progress ', percentComplete);\n\n $form.eventData.onprogress = result;\n\n triggerEvent(gina, $target, 'progress.' + id, result)\n };\n\n // catching timeout\n xhr.ontimeout = function (event) {\n result = {\n 'status': 408,\n 'error': 'Request Timeout'\n };\n\n $form.eventData.ontimeout = result;\n\n // intercept upload\n if ( /^gina\\-upload/i.test(id) )\n onUpload(gina, $target, 'error', id, result);\n \n triggerEvent(gina, $target, 'error.' + id, result);\n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', result);\n };\n\n\n // sending\n if (!data)\n data = event.detail.data;\n\n if (data) {\n\n var hasBinaries = false;\n \n if ( typeof(data) == 'object' ) {\n\n var binaries = []\n , b = 0\n , newData = {};\n\n try {\n if ( !(data instanceof FormData) ) {\n data = JSON.stringify(data)\n } else {\n var uploadGroup = event.currentTarget.getAttribute('data-gina-form-upload-group') || 'untagged';\n for (var [key, value] of data.entries()) {\n // file upload case\n if (value instanceof File) {\n if (!hasBinaries)\n hasBinaries = true;\n \n binaries[b] = {\n key: key,\n group: uploadGroup, // `untagged` by default\n file: value,\n bin: ''\n };\n \n ++b;\n } else {\n newData[key] = value\n }\n \n }\n }\n\n \n if (hasBinaries && binaries.length > 0) {\n\n // We need a separator to define each part of the request\n var boundary = '--ginaWKBoundary' + uuid.v4().replace(/\\-/g, ''); \n \n \n return processFiles(binaries, boundary, '', 0, function onComplete(err, data, done) {\n \n if (err) {\n //throw err\n // intercept upload\n if ( /^gina\\-upload/i.test(id) )\n onUpload(gina, $target, 'error', id, err);\n \n triggerEvent(gina, $target, 'error.' + id, err);\n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', err);\n } else {\n\n if (done) {\n xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);\n xhr.send(data);\n \n $form.sent = true;\n if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) {\n // update toolbar\n if (!gina.forms.sent)\n gina.forms.sent = {};\n \n var objCallback = {\n id : id,\n sent : ( typeof(data) == 'string' ) ? JSON.parse(data) : data\n };\n \n window.ginaToolbar.update('forms', objCallback);\n }\n }\n\n done = false;\n\n return false;\n } \n });\n \n } else if ( typeof(newData) != 'undefined' && newData.count() > 0 ) { // without file\n data = JSON.stringify(newData)\n }\n \n \n } catch (err) {\n // intercept upload\n if ( /^gina\\-upload/i.test(id) )\n onUpload(gina, $target, 'error', id, err);\n \n triggerEvent(gina, $target, 'error.' + id, err);\n \n if (hFormIsRequired)\n triggerEvent(gina, $target, 'error.' + id + '.hform', err);\n }\n }\n //console.debug('sending -> ', data);\n if (!hasBinaries) {\n if (typeof (enctype) != 'undefined' && enctype != null && enctype != '') {\n xhr.setRequestHeader('Content-Type', enctype);\n }\n xhr.send(data)\n }\n\n } else {\n\n if ( typeof(enctype) != 'undefined' && enctype != null && enctype != ''){\n xhr.setRequestHeader('Content-Type', enctype);\n }\n xhr.send()\n }\n\n $form.sent = true;\n if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) {\n // update toolbar\n if (!gina.forms.sent)\n gina.forms.sent = {};\n\n var objCallback = {\n id : id,\n sent : ( typeof(data) == 'string' ) ? JSON.parse(data) : data\n };\n\n window.ginaToolbar.update('forms', objCallback);\n }\n }\n }\n \n var onUpload = function(gina, $target, status, id, data) {\n \n var uploadProperties = $target.uploadProperties || null;\n // FYI\n // { \n // id : String,\n // $form : $Object,\n // mandatoryFields : Array,\n // uploadFields : ObjectList\n // hasPreviewContainer : Boolean,\n // previewContainer : $Object\n // }\n \n if ( !uploadProperties )\n throw new Error('No uploadProperties found !!');\n // parent form\n // var $mainForm = uploadProperties.$form;\n var $uploadTriger = document.getElementById(uploadProperties.uploadTriggerId);\n var searchArr = null\n , name = null\n , $previewContainer = null\n , files = data.files || []\n , $error = null\n ;\n // reset previewContainer\n if ( uploadProperties.hasPreviewContainer ) { \n $previewContainer = document.getElementById(uploadProperties.previewContainer.id);\n if ($previewContainer)\n $previewContainer.innerHTML = '';\n }\n \n if (uploadProperties.errorField) {\n $error = document.getElementById(uploadProperties.errorField)\n }\n \n \n //reset errors\n if ($error)\n $error.style.display = 'none';\n \n if ($error && status != 'success') { // handle errors first\n // console.error('[ mainUploadError ] ', status, data)\n var errMsg = data.message || data.error; \n \n $error.innerHTML = '<p>'+ errMsg +'</p>';\n fadeIn($error);\n } else if(!$error && status != 'success') {\n throw new Error(errMsg)\n } else {\n \n var fieldsObjectList = null\n , $li = null\n , maxWidth = null\n , ratio = null\n ;\n for (var f = 0, fLen = files.length; f<fLen; ++f) {\n \n // creating reset link\n let resetLinkId = $previewContainer.id.replace(/\\-preview/, '-'+f+'-reset-trigger');\n let resetLinkNeedToBeAdded = false;\n let $resetLink = document.getElementById(resetLinkId);\n let defaultClassNameArr = ['reset','js-upload-reset'];\n if (!$resetLink) {\n resetLinkNeedToBeAdded = true;\n $resetLink = document.createElement('A');\n $resetLink.href = '#';\n $resetLink.innerHTML = $uploadTriger.getAttribute('data-gina-form-upload-reset-label') || 'Reset';\n $resetLink.className = defaultClassNameArr.join(' '); \n $resetLink.id = resetLinkId;\n } else {\n if ( /a/i.test($resetLink.tagName) ) {\n $resetLink.href = '#';\n }\n if ( !$resetLink.innerHTML || $resetLink.innerHTML == '' ) {\n $resetLink.innerHTML = $uploadTriger.getAttribute('data-gina-form-upload-reset-label') || 'Reset';\n }\n if ( typeof($resetLink.className) == 'undefined' ) {\n $resetLink.className = \"\";\n }\n let classNameArr = merge($resetLink.className.split(/\\s+/g), defaultClassNameArr);\n $resetLink.className = classNameArr.join(' ');\n } \n $resetLink.style.display = 'none';\n \n // image preview\n if ( typeof(files[f].preview) == 'undefined' \n && uploadProperties.hasPreviewContainer \n && /^image/.test(files[f].mime)\n && files[f].location != ''\n ) {\n let $img = document.createElement('IMG');\n $img.src = files[f].tmpUri;\n $img.style.display = 'none';\n $img.setAttribute('data-upload-original-filename', files[f].originalFilename);\n $img.setAttribute('data-upload-reset-link-id', $resetLink.id);\n \n // TODO - Remove this; we don't want it by default, the dev can force it by hand if needed\n // if (files[f].width) {\n // $img.width = files[f].width;\n // }\n // if (files[f].height) {\n // $img.height = files[f].height;\n // }\n \n maxWidth = $previewContainer.getAttribute('data-preview-max-width') || null;\n if ( $img.width && maxWidth && $img.width > maxWidth ) {\n ratio = $img.width / maxWidth;\n $img.width = maxWidth;\n $img.height = $img.height / ratio;\n } else if (!$img.width && maxWidth ) {\n $img.width = maxWidth\n }\n \n if ( /ul/i.test(uploadProperties.previewContainer.tagName) ) {\n $li = document.createElement('LI');\n $li.className = 'item';\n $li.appendChild($img);\n $previewContainer.appendChild($li); \n } else {\n $previewContainer.appendChild($img);\n }\n fadeIn($img);\n }\n // fill the fields to be saved ;) \n fieldsObjectList = uploadProperties.uploadFields[f];\n var $elIgnored = null;\n for (var key in fieldsObjectList) { \n // update field value\n if ( \n key == 'name' && fieldsObjectList[key].value != '' \n || !files[f][key]\n || key == 'preview' && typeof(files[f][key]) == 'undefined'\n || /(height|width)/i.test(key) && !/^image/.test(files[f].mime)\n ) {\n if ( /(preview|height|width)/i.test(key) ) {\n $elIgnored = document.getElementById(fieldsObjectList[key].id);\n if ( $elIgnored )\n $elIgnored.parentNode.removeChild($elIgnored);\n }\n continue;\n }\n //fieldsObjectList[key].value = (/object/i.test(typeof(files[f][key])) ) ? JSON.stringify( files[f][key] ) : files[f][key];\n fieldsObjectList[key].value = files[f][key];\n // update submited $fields ??\n \n // handle preview\n if ( key == 'preview' ) {\n \n for (var previewKey in files[f][key]) { \n if ( typeof(files[f][key][previewKey]) != 'undefined' && typeof(fieldsObjectList[key][previewKey]) != 'undefined' ) {\n fieldsObjectList[key][previewKey].value = files[f][key][previewKey];\n }\n \n // with preview\n if ( previewKey == 'tmpUri' && uploadProperties.hasPreviewContainer ) { \n \n // // creating reset link\n // let resetLinkId = $previewContainer.id.replace(/\\-preview/, '-'+f+'-reset-trigger');\n // let resetLinkNeedToBeAdded = false;\n // let $resetLink = document.getElementById(resetLinkId);\n // let defaultClassNameArr = ['reset','js-upload-reset'];\n // if (!$resetLink) {\n // resetLinkNeedToBeAdded = true;\n // $resetLink = document.createElement('A');\n // $resetLink.href = '#';\n // $resetLink.innerHTML = $uploadTriger.getAttribute('data-gina-form-upload-reset-label') || 'Reset';\n // $resetLink.className = defaultClassNameArr.join(' '); \n // $resetLink.id = resetLinkId;\n // } else {\n // if ( /a/i.test($resetLink.tagName) ) {\n // $resetLink.href = '#';\n // }\n // if ( !$resetLink.innerHTML || $resetLink.innerHTML == '' ) {\n // $resetLink.innerHTML = $uploadTriger.getAttribute('data-gina-form-upload-reset-label') || 'Reset';\n // }\n // if ( typeof($resetLink.className) == 'undefined' ) {\n // $resetLink.className = \"\";\n // }\n // let classNameArr = merge($resetLink.className.split(/\\s+/g), defaultClassNameArr);\n // $resetLink.className = classNameArr.join(' ');\n // } \n // $resetLink.style.display = 'none';\n \n \n // creating IMG tag\n let $img = document.createElement('IMG');\n $img.src = files[f][key].tmpUri;\n $img.style.display = 'none';\n // retrieve img `originalFilename` (not the preview img[key] `originalFilename`)\n // these 2 metadatas will be used to remove files from the server\n $img.setAttribute('data-upload-original-filename', files[f].originalFilename);\n $img.setAttribute('data-upload-preview-original-filename', files[f][key].originalFilename);\n // in order to retrieve and remove reset link\n $img.setAttribute('data-upload-reset-link-id', $resetLink.id);\n \n maxWidth = $previewContainer.getAttribute('data-preview-max-width') || null;\n if ( maxWidth ) {\n $img.width = maxWidth\n }\n \n if ( /ul/i.test(uploadProperties.previewContainer.tagName) ) {\n $li = document.createElement('LI');\n $li.className = 'item';\n $li.appendChild($img);\n // if (resetLinkNeedToBeAdded)\n // $li.appendChild($resetLink);\n \n $previewContainer.appendChild($li); \n } else {\n $previewContainer.appendChild($img);\n // if (resetLinkNeedToBeAdded)\n // $previewContainer.appendChild($resetLink);\n }\n fadeIn($img);\n // // bind reset trigger\n // bindUploadResetOrDeleteTrigger('reset', $uploadTriger, f);\n // fadeIn($resetLink);\n }\n } \n } \n } // EO for \n \n if (uploadProperties.hasPreviewContainer) {\n if ( /ul/i.test(uploadProperties.previewContainer.tagName) ) {\n $li = document.createElement('LI');\n $li.className = 'item';\n if (resetLinkNeedToBeAdded)\n $li.appendChild($resetLink); \n $previewContainer.appendChild($li); \n } else { \n if (resetLinkNeedToBeAdded)\n $previewContainer.appendChild($resetLink);\n }\n }\n // bind reset trigger\n bindUploadResetOrDeleteTrigger('reset', $uploadTriger, f);\n fadeIn($resetLink);\n } // EO for f\n }\n }\n \n /**\n * onUploadResetOrDelete\n * \n * @param {object} $uploadTrigger \n * @param {string} bindingType - `reset` or `delete`\n * @returns \n */\n var onUploadResetOrDelete = function($uploadTrigger, bindingType) {\n console.debug(bindingType + ' input files');\n var isOnResetMode = ( /reset/i.test(bindingType) ) ? true : false\n , uploadPreviewId = $uploadTrigger.id +'-preview'\n , $uploadPreview = document.getElementById(uploadPreviewId);\n \n var childNodeFile = null\n , childNodeFilePreview = null\n , childNodes = $uploadPreview.childNodes\n , $resetLink = null\n , files = $uploadTrigger.customFiles\n , filesToBeRemoved = []\n ;\n \n for (let i = 0, len = childNodes.length; i < len; i++) {\n // only look for IMG tags\n if ( /img/i.test(childNodes[i].tagName) ) {\n if (isOnResetMode) {\n childNodeFile = childNodes[i].getAttribute('data-upload-original-filename');\n filesToBeRemoved.push(childNodeFile);\n childNodeFilePreview = childNodes[i].getAttribute('data-upload-preview-original-filename');\n if (childNodeFilePreview) {\n filesToBeRemoved.push(childNodeFilePreview);\n }\n } else {\n let file = childNodes[i].src.substr(childNodes[i].src.lastIndexOf('/')+1);\n childNodeFile = file;\n filesToBeRemoved.push(childNodeFile);\n }\n \n // remove file from input.files\n for (let f = 0, fLen = files.length; f < fLen; f++) { \n if (files[f].name == childNodeFile) { \n // get resetLink element\n if (isOnResetMode) {\n $resetLink = document.getElementById( childNodes[i].getAttribute('data-upload-'+ bindingType +'-link-id') );\n } else {\n $resetLink = document.getElementById( files[f].deleteLinkId );\n }\n \n // hide reset or delete link & image\n $resetLink.style.display = 'none';\n childNodes[i].style.display = 'none';\n \n // remove file from input.files \n files.splice(f, 1);\n // Since `$uploadTrigger.files` isFrozen & isSealed\n $uploadTrigger.customFiles = files;\n if (isOnResetMode) {\n $uploadTrigger.value = files.join(', C:\\\\fakepath\\\\');\n } \n \n // update form files for validation & submit/send\n let re = new RegExp('^'+($uploadTrigger.name+'['+f+']').replace(/\\-|\\[|\\]|\\./g, '\\\\$&'));\n for ( let d = 0, dLen = $uploadTrigger.form.length; d < dLen; d++) {\n // data-gina-form-upload-is-locked\n // this exception prevent `tagged datas` to be deleted on image delete\n let isLocked = $uploadTrigger.form[d].dataset.ginaFormUploadIsLocked || false;\n if ( re.test($uploadTrigger.form[d].name) && !/true/i.test(isLocked) ) {\n $uploadTrigger.form[d].remove();\n dLen--;\n d--;\n //update toolbar\n if (gina && GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) { \n try {\n // update toolbar\n window.ginaToolbar.update('data-xhr', {files: files}); \n } catch (err) {\n throw err\n }\n }\n }\n }\n // remove file from the server - filesToBeRemoved \n let url = $uploadTrigger.getAttribute('data-gina-form-upload-'+ bindingType +'-action');\n if ( !url || typeof(url) == 'undefined' || url == '' || /404/.test(url) ) {\n throw new Error('input file `'+ $uploadTrigger.id +'` error: `data-gina-form-upload-'+bindingType+'-action` is required. You need to provide a valide url.');\n }\n let method = $uploadTrigger.getAttribute('data-gina-form-upload-'+ bindingType +'-method');\n if ( !method || typeof(method) == 'undefined' || method == '') { \n if (isOnResetMode) {\n method = 'POST';\n } else {\n method = (filesToBeRemoved.length > 1) ? 'POST': 'DELETE';\n console.warn('`data-gina-form-upload-'+ bindingType +'-method` was not defined. Switching to `'+ method +'` by default.'); \n }\n } else {\n method = method.toUpperCase();\n }\n let isSynchrone = $uploadTrigger.getAttribute('data-gina-form-upload-'+ bindingType +'-is-synchrone');\n if ( /null/i.test(isSynchrone) || typeof(method) == 'undefined' || method == '' ) {\n isSynchrone = true;\n }\n \n let xhrOptions = {\n url: url,\n method: method,\n isSynchrone: isSynchrone,\n headers : {\n // to upload, use `multipart/form-data` for `enctype`\n 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',\n // cross domain is enabled by default, but you need to setup `Access-Control-Allow-Origin`\n 'X-Requested-With': 'XMLHttpRequest' // in case of cross domain origin\n }\n };\n let xhr = setupXhr(xhrOptions);\n //handleXhr(xhr);\n if ( /GET|DELETE/i.test(method) ) {\n xhr.send();\n } else {\n xhr.send(JSON.stringify({ files: filesToBeRemoved }));\n } \n \n // when there is no more files to preview, restore input file visibility\n // display upload input\n if ( /none/i.test(window.getComputedStyle($uploadTrigger).display) ) {\n // eg.: visibility could be delegated to a parent element such as label or a div \n if ( /none/i.test($uploadTrigger.parentElement.style.display) ) {\n $uploadTrigger.parentElement.style.display = 'block';\n return;\n }\n $uploadTrigger.style.display = 'block';\n }\n \n // remove reset link event\n removeListener(gina, $uploadResetTrigger, 'click', function onUploadResetTriggerEventRemoved() {\n // remove link & image - must be done last\n $resetLink.remove();\n childNodes[i].remove();\n }); \n len--;\n i--;\n break;\n }\n } // EO for\n }\n }\n } \n\n /**\n * Convert <Uint8Array|Uint16Array|Uint32Array> to <String>\n * @param {array} buffer\n * @param {number} [byteLength] e.g.: 8, 16 or 32\n * \n * @return {string} stringBufffer\n */\n var ab2str = function(event, buf, byteLength) {\n\n var str = '';\n var ab = null;\n\n if ( typeof(byteLength) == 'undefined' ) {\n var byteLength = 8;\n }\n\n \n var bits = (byteLength / 8) \n\n\n switch (byteLength) {\n case 8:\n ab = new Uint8Array(buf);\n break;\n case 16:\n ab = new Uint16Array(buf);\n break;\n\n case 32:\n ab = new Uint32Array(buf);\n break;\n \n default:\n ab = new Uint8Array(buf); \n break; \n\n }\n\n var abLen = ab.length;\n var CHUNK_SIZE = Math.pow(2, 8) + bits;\n var offset = 0, len = null, subab = null;\n \n for (; offset < abLen; offset += CHUNK_SIZE) {\n len = Math.min(CHUNK_SIZE, abLen - offset);\n subab = ab.subarray(offset, offset + len);\n str += String.fromCharCode.apply(null, subab);\n }\n \n return str;\n }\n\n\n var processFiles = function(binaries, boundary, data, f, onComplete) {\n\n var reader = new FileReader();\n \n // progress\n // reader.addEventListener('progress', (e) => {\n // var percentComplete = '0';\n // if (e.lengthComputable) {\n // percentComplete = e.loaded / e.total;\n // percentComplete = parseInt(percentComplete * 100);\n\n // }\n\n // // var result = {\n // // 'status': 100,\n // // 'progress': percentComplete\n // // };\n \n // console.debug('progress', percentComplete);\n\n // //$form.eventData.onprogress = result;\n\n // //triggerEvent(gina, $target, 'progress.' + id, result)\n // });\n\n reader.addEventListener('load', function onReaderLoaded(e) {\n\n e.preventDefault();\n \n // var percentComplete = '0';\n // if (e.lengthComputable) {\n // percentComplete = e.loaded / e.total;\n // percentComplete = parseInt(percentComplete * 100);\n \n // console.debug('progress', percentComplete);\n // }\n \n\n try {\n \n var bin = ab2str(e, this.result);\n ; \n binaries[this.index].bin += bin;\n\n if (!binaries[this.index].file.type) {\n binaries[this.index].file.type = 'application/octet-stream'\n }\n\n } catch (err) {\n return onComplete(err, null, true);\n }\n\n // Start a new part in our body's request\n data += \"--\" + boundary + \"\\r\\n\";\n\n // Describe it as form data\n data += 'Content-Disposition: form-data; '\n // Define the name of the form data\n + 'name=\"' + binaries[this.index].key + '\"; ' \n // Define the upload group\n + 'group=\"' + binaries[this.index].group + '\"; '\n // Provide the real name of the file\n + 'filename=\"' + binaries[this.index].file.name + '\"\\r\\n'\n // And the MIME type of the file\n + 'Content-Type: ' + binaries[this.index].file.type + '\\r\\n'\n // File length\n + 'Content-Length: ' + binaries[this.index].bin.length + '\\r\\n'\n // There's a blank line between the metadata and the data\n + '\\r\\n';\n\n // Append the binary data to our body's request\n data += binaries[this.index].bin + '\\r\\n';\n\n ++this.index;\n // is last file ?\n if (this.index == binaries.length) {\n // Once we are done, \"close\" the body's request\n data += \"--\" + boundary + \"--\";\n\n onComplete(false, data, true);\n\n } else { // process next file\n processFiles(binaries, boundary, data, this.index, onComplete)\n } \n }, false);\n\n reader.index = f;\n binaries[f].bin = '';\n\n reader.readAsArrayBuffer(binaries[f].file);\n //reader.readAsBinaryString(binaries[f].file);\n }\n\n \n var listenToXhrEvents = function($form) {\n \n //data-gina-form-event-on-submit-success\n var htmlSuccesEventCallback = $form.target.getAttribute('data-gina-form-event-on-submit-success') || null;\n if (htmlSuccesEventCallback != null) {\n\n if ( /\\((.*)\\)/.test(htmlSuccesEventCallback) ) {\n eval(htmlSuccesEventCallback)\n } else {\n $form.on('success.hform', window[htmlSuccesEventCallback])\n }\n }\n //data-gina-form-event-on-submit-error\n var htmlErrorEventCallback = $form.target.getAttribute('data-gina-form-event-on-submit-error') || null;\n if (htmlErrorEventCallback != null) {\n if ( /\\((.*)\\)/.test(htmlErrorEventCallback) ) {\n eval(htmlErrorEventCallback)\n } else {\n $form.on('error.hform', window[htmlErrorEventCallback])\n }\n } \n \n }\n \n\n var destroy = function(formId) {\n var $form = null, _id = formId;\n\n if ( !instance['$forms'] )\n throw new Error('`$forms` collection not found');\n\n\n if ( typeof(_id) == 'undefined') {\n if ( typeof(this.id) != 'undefined' && this.id != '' && this.id != null ) {\n _id = this.id\n } else {\n throw new Error('[ FormValidator::destroy(formId) ] `formId` is missing')\n }\n }\n\n if ( typeof(_id) == 'string') {\n _id = _id.replace(/\\#/, '')\n } else if ( typeof(_id) == 'object' && !Array.isArray(_id) ) { // weird exception\n var $target = _id.form;\n _id = $target.getAttribute('id') || 'form.'+uuid.v4();\n\n $target.setAttribute('id', _id);// just in case\n\n } else {\n throw new Error('[ FormValidator::destroy(formId) ] `formId` should be a `string`');\n }\n\n if ( typeof(instance['$forms'][_id]) != 'undefined' ) {\n $form = instance['$forms'][_id]\n } else if ( typeof(this.binded) != 'undefined' ) {\n $form = this;\n }\n\n if ($form) { \n\n addListener(gina, $form.target, 'destroy.' + _id, function(event) {\n\n cancelEvent(event);\n\n delete instance['$forms'][_id];\n removeListener(gina, event.currentTarget, event.type);\n removeListener(gina, event.currentTarget,'destroy');\n });\n \n // remove existing listeners\n $form = unbindForm($form);\n\n //triggerEvent(gina, instance['$forms'][_id].target, 'destroy.' + _id);\n triggerEvent(gina, $form.target, 'destroy.' + _id);\n\n } else {\n throw new Error('[ FormValidator::destroy(formId) ] `'+_id+'` not found');\n }\n\n }\n \n /**\n * cleanupInstanceRules\n * Will remove _case_ condition for empty rules\n * Used to remove empty `@import` after `checkForRulesImports` is called\n * \n */\n var cleanupInstanceRules = function() {\n var rule = ( typeof(arguments[0]) != 'undefined' ) ? arguments[0] : instance.rules; \n for (let r in rule) {\n let props = Object.getOwnPropertyNames(rule[r]);\n let p = 0, pLen = props.length;\n let hasCases = false, caseName = null;\n while (p < pLen) {\n if ( /^\\_case\\_/.test(props[p]) ) {\n hasCases = true;\n caseName = props[p];\n break;\n }\n p++\n }\n \n if ( !hasCases && typeof(rule[r]) == 'object') {\n cleanupInstanceRules(rule[r]);\n } \n \n if (caseName && Array.isArray(rule[r][caseName].conditions) && rule[r][caseName].conditions.length > 0) {\n let c = 0, len = rule[r][caseName].conditions.length;\n while (c < len) {\n if ( \n typeof(rule[r][caseName].conditions[c].rules) != 'undefined'\n && rule[r][caseName].conditions[c].rules.count() == 0 \n ) {\n rule[r][caseName].conditions.splice(c, 1);\n len--;\n c--;\n }\n c++;\n }\n } \n }\n }\n \n var checkForRulesImports = function (rules) {\n // check if rules has imports & replace\n var rulesStr = JSON.stringify(rules);\n var importedRules = rulesStr.match(/(\\\"@import\\s+[-_a-z A-Z 0-9/.]+\\\")/g) || [];\n // remove duplicate\n var filtered = [];\n for (let d = 0, dLen = importedRules.length; d < dLen; d++) {\n if (filtered.indexOf(importedRules[d]) < 0) {\n filtered.push(importedRules[d])\n }\n }\n importedRules = filtered;\n // TODO - complete mergingRules integration\n var mergingRules = rulesStr.match(/(\\\"_merging(.*))(\\s+\\:|\\:)(.*)(\\\",|\\\")/g)\n var isMerging = false;\n if (!instance.rules) {\n instance.rules = {}\n }\n if (importedRules && importedRules.length > 0) {\n var ruleArr = [], rule = {}, tmpRule = null, re = null;\n for (let r = 0, len = importedRules.length; r<len; ++r) {\n let importPath = importedRules[r].replace(/(@import\\s+|\\\"|\\')/g, '');\n ruleArr = importPath.replace(/(@import\\s+|\\\"|\\')/g, '').split(/\\s/g);\n // [\"\"@import client/form\", \"\"@import project26/edit demo/edit\"]\n //console.debug('ruleArr -> ', ruleArr, importedRules[r]);\n for (let i = 0, iLen = ruleArr.length; i<iLen; ++i) {\n tmpRule = ruleArr[i].replace(/\\//g, '.').replace(/\\-/g, '.');\n if ( typeof(instance.rules[ tmpRule ]) != 'undefined' ) {\n let rule = JSON.stringify(instance.rules[ tmpRule ]);\n let strRule = JSON.parse(rule);\n if ( typeof(strRule['_comment']) != 'undefined' ) {\n strRule['_comment'] += '\\n';\n } else {\n strRule['_comment'] = '';\n } \n strRule['_comment'] += 'Imported from `'+ importPath +'`';\n rule = JSON.stringify(strRule);\n rulesStr = rulesStr.replace(new RegExp(importedRules[r], 'g'), rule);\n // also need to replace in instance.rules\n instance.rules = JSON.parse(JSON.stringify(instance.rules).replace(new RegExp(importedRules[r], 'g'), '{}'));\n } else {\n console.warn('[formValidator:rules] <@import error> on `'+importedRules[r]+'`: rule `'+ruleArr[i]+'` not found. Ignoring.');\n continue;\n }\n }\n //console.debug('replacing ', importedRules[r]);\n re = new RegExp(importedRules[r]);\n isMerging = ( mergingRules && re.test(mergingRules.join()) ) ? true : false;\n if( isMerging ) {\n \n for (let m = 0, mLen = mergingRules.length; m < mLen; m++) {\n if ( re.test(mergingRules[m]) ) { \n let tmpStr = JSON.stringify(rule);\n tmpStr = tmpStr.substr(1, tmpStr.length-1);// removing ->{ ... }<-\n // is last ?\n if (m < mLen-1) {\n tmpStr += ','\n }\n try {\n rulesStr = rulesStr.replace( new RegExp(mergingRules[m], 'g'), tmpStr); \n // also need to replace in instance.rules\n instance.rules = JSON.parse(JSON.stringify(instance.rules).replace(new RegExp(mergingRules[m], 'g'), '{}'));\n } catch (error) {\n throw error\n } \n }\n }\n \n }\n rule = {}\n }\n\n rules = JSON.parse(rulesStr);\n parseRules(rules, '');\n \n try {\n cleanupInstanceRules();\n } catch (err) {\n console.error(err.stack);\n } \n }\n \n return rules;\n }\n\n var init = function (rules) {\n\n if (gina.hasValidator) {\n \n instance = merge(instance, gina.validator);\n instance.on('init', function(event) {\n instance.isReady = true;\n triggerEvent(gina, instance.target, 'ready.' + instance.id, instance)\n })\n } else {\n setupInstanceProto();\n instance.on('init', function onValidatorInit(event) {\n // parsing rules\n if ( typeof(rules) != 'undefined' && rules.count() ) {\n try { \n parseRules(rules, '');\n rules = checkForRulesImports(rules);\n // making copy\n if ( typeof(gina.forms.rules) == 'undefined' || !gina.forms.rules) {\n gina.forms.rules = rules\n } else { // inherits\n gina.forms.rules = merge(gina.forms.rules, rules, true);\n } \n // update instance.rules\n instance.rules = merge(instance.rules, JSON.clone(gina.forms.rules), true);\n } catch (err) {\n throw (err)\n }\n }\n \n if ( !local.rules.count() ) {\n local.rules = JSON.clone(instance.rules);\n }\n \n\n $validator.setOptions = setOptions;\n $validator.getFormById = getFormById;\n $validator.validateFormById = validateFormById;\n $validator.resetErrorsDisplay = resetErrorsDisplay;\n $validator.resetFields = resetFields;\n $validator.handleErrorsDisplay = handleErrorsDisplay;\n $validator.submit = submit;\n $validator.send = send;\n $validator.unbind = unbindForm;\n $validator.bind = bindForm;\n $validator.reBind = reBindForm;\n $validator.destroy = destroy;\n\n var id = null\n , $target = null\n , i = 0\n , $forms = []\n , $allForms = document.getElementsByTagName('form');\n\n\n // form has rule ?\n for (var f=0, len = $allForms.length; f<len; ++f) {\n // preparing prototype (need at least an ID for this)\n \n if ($allForms[f].getAttribute) {\n id = $allForms[f].getAttribute('id') || 'form.' + uuid.v4();\n if ( id !== $allForms[f].getAttribute('id') ) {\n $allForms[f].setAttribute('id', id)\n }\n } else {\n id = 'form.' + uuid.v4();\n $allForms[f].setAttribute('id', id)\n }\n\n //$allForms[f]['id'] = $validator.id = id;\n $validator.id = id;\n\n //if ( typeof($allForms[f].getAttribute('id')) != 'undefined' && $allForms[f].id != 'null' && $allForms[f].id != '') {\n\n $validator.target = $allForms[f];\n instance.$forms[id] = merge({}, $validator);\n\n var customRule = $allForms[f].getAttribute('data-gina-form-rule');\n\n if (customRule) {\n customRule = customRule.replace(/\\-|\\//g, '.');\n if ( typeof(rules) != 'undefined' ) {\n instance.$forms[id].rules[customRule] = instance.rules[customRule] = local.rules[customRule] = merge(JSON.clone( eval('gina.forms.rules.'+ customRule)), instance.rules[customRule]);\n }\n if ( typeof(local.rules[customRule]) == 'undefined' ) {\n throw new Error('['+id+'] no rule found with key: `'+customRule+'`. Please check if json is not malformed @ /forms/rules/' + customRule.replace(/\\./g, '/') +'.json'); \n }\n customRule = instance.rules[customRule];\n }\n\n // finding forms handled by rules\n if ( \n typeof(id) == 'string' \n && typeof(local.rules[id.replace(/\\-/g, '.')]) != 'undefined'\n ||\n typeof(customRule) == 'object'\n ) {\n $target = instance.$forms[id].target;\n if (customRule) {\n bindForm($target, customRule)\n } else {\n bindForm($target)\n }\n\n ++i\n }\n // TODO - remove this\n // migth not be needed anymore \n else {\n // weird exception when having in the form an element with name=\"id\"\n if ( typeof($allForms[f].id) == 'object' ) {\n delete instance.$forms[$allForms[f].id];\n\n var _id = $allForms[f].attributes.getNamedItem('id').nodeValue || 'form.'+uuid.v4();\n\n $allForms[f].setAttribute('id', _id);\n $allForms[f]['id'] = _id;\n\n $validator.target = $allForms[f];\n instance.$forms[_id] = merge({}, $validator);\n\n $target = instance.$forms[_id].target;\n if (customRule) {\n bindForm($target, customRule)\n } else {\n bindForm($target)\n }\n } else {\n\n $target = instance.$forms[$allForms[f].id].target;\n if (customRule) {\n bindForm($target, customRule)\n } else {\n bindForm($target)\n }\n }\n }\n //}\n\n }\n\n\n // setting up AJAX\n if (window.XMLHttpRequest) { // Mozilla, Safari, ...\n xhr = new XMLHttpRequest();\n } else if (window.ActiveXObject) { // IE\n try {\n xhr = new ActiveXObject(\"Msxml2.XMLHTTP\");\n } catch (e) {\n try {\n xhr = new ActiveXObject(\"Microsoft.XMLHTTP\");\n }\n catch (e) {}\n }\n }\n \n \n\n instance.isReady = true;\n gina.hasValidator = true;\n gina.validator = instance;\n triggerEvent(gina, instance.target, 'ready.' + instance.id, instance);\n });\n\n }\n\n instance.initialized = true;\n return instance\n }\n\n var initForm = function ($form) {\n\n var customRule = null\n , rules = ( typeof(local.rules.count() > 0 ) ) ? local.rules : instance.rules\n ;\n\n if ($form.getAttribute) {\n id = $form.getAttribute('id') || 'form.' + uuid.v4();\n if (id !== $form.getAttribute('id')) {\n $form.setAttribute('id', id)\n }\n } else {\n id = 'form.' + uuid.v4();\n $form.setAttribute('id', id)\n }\n\n $form.id = $validator.id = id;\n\n if (typeof ($form.id) != 'undefined' && $form.id != 'null' && $form.id != '') {\n\n $validator.target = $form;\n instance.$forms[$form.id] = merge({}, $validator);\n\n customRule = $form.getAttribute('data-gina-form-rule');\n\n if (customRule) {\n customRule = customRule.replace(/\\-|\\//g, '.');\n if ( typeof(rules[customRule]) == 'undefined') {\n customRule = null;\n throw new Error('[' + $form.id + '] no rule found with key: `' + customRule + '`');\n } else {\n customRule = rules[customRule]\n }\n }\n\n // finding forms handled by rules\n if (typeof ($form.id) == 'string' && typeof (rules[$form.id.replace(/\\-/g, '.')]) != 'undefined') {\n $target = instance.$forms[$form.id].target;\n if (customRule) {\n bindForm($target, customRule)\n } else {\n bindForm($target)\n }\n\n } else {\n // weird exception when having in the form an element with name=\"id\"\n if (typeof ($form.id) == 'object') {\n delete instance.$forms[$form.id];\n\n var _id = $form.attributes.getNamedItem('id').nodeValue || 'form.' + uuid.v4();\n\n $form.setAttribute('id', _id);\n $form.id = _id;\n\n $validator.target = $form;\n instance.$forms[_id] = merge({}, $validator);\n\n $target = instance.$forms[_id].target;\n if (customRule) {\n bindForm($target, customRule)\n } else {\n bindForm($target)\n }\n } else {\n\n $target = instance.$forms[$form.id].target;\n if (customRule) {\n bindForm($target, customRule)\n } else {\n bindForm($target)\n }\n }\n }\n } \n }\n\n /**\n * parseRules - Preparing rules paths\n *\n * @param {object} rules\n * @param {string} tmp - path\n * */\n var parseRules = function(rules, tmp) {\n var _r = null;\n for (var r in rules) {\n\n if ( typeof(rules[r]) == 'object' && typeof(instance.rules[tmp + r]) == 'undefined' ) {\n\n _r = r;\n if (/\\[|\\]/.test(r) ) { // must be a real path\n _r = r.replace(/\\[/g, '.').replace(/\\]/g, '');\n }\n \n instance.rules[tmp + _r] = rules[r];\n \n //delete instance.rules[r];\n parseRules(rules[r], tmp + _r +'.');\n }\n }\n }\n \n var getRuleObjByName = function(ruleName) {\n \n if ( typeof(local.rules[ruleName]) != 'undefined' ) {\n return local.rules[ruleName]\n }\n var rules = null;\n // just in case : many ways to access this method\n if ( typeof(instance.rules[ruleName]) == 'undefined' ) { \n parseRules(local.rules, '');\n local.rules = checkForRulesImports(local.rules);\n rules = local.rules[ruleName];\n if ( !rules ) {\n return {}\n }\n } else {\n rules = instance.rules[ruleName]\n }\n \n var ruleObj = JSON.clone(rules)\n , re = new RegExp('^'+ruleName)\n , propRe = new RegExp('^'+ruleName +'.')\n , propName = null\n ;\n \n var rulesFromPath = function(obj, keys, val, originalRuleObj, field, i, len) {\n if (!keys.length) { \n return\n }\n \n var _id = Object.getOwnPropertyNames(obj)[0];\n var _key = keys[0];\n var nextFieldName = null;\n if ( field == '') {\n field += _key;\n nextFieldName = field\n } else {\n nextFieldName = field + '['+ _key + ']'\n }\n \n if ( keys.length == 1) {\n // obj[ _key ] = ( \n // typeof(obj[ _key ]) == 'undefined' \n // && typeof(val) == 'object' \n // && Array.isArray(val)\n // ) ? [] : {} ;\n \n obj[ _id ] = merge(obj[ _id ], val, true); \n \n // if ( \n // typeof(originalRuleObj[nextFieldName]) != 'undefined' \n // //&& typeof(originalRuleObj[nextFieldName][_key]) != 'undefined' \n // ) {\n \n // originalRuleObj[nextFieldName] = val//merge(originalRuleObj[nextFieldName], val, true);\n // //if ( typeof(originalRuleObj[nextFieldName][_key]) != 'undefined' ) {\n // // originalRuleObj[nextFieldName][_key] = val\n // //}// else {\n // // originalRuleObj[nextFieldName][_key] = merge(originalRuleObj[nextFieldName][_key], val, true);\n // //}\n \n \n // } else if ( \n // typeof(originalRuleObj[field]) != 'undefined' \n // //&& typeof(originalRuleObj[field][_key]) != 'undefined'\n // ) {\n // originalRuleObj[field] = val\n // //originalRuleObj[field] = merge(originalRuleObj[field], val, true);\n // //if ( typeof(originalRuleObj[field][_key]) != 'undefined' ) { \n // // originalRuleObj[field][_key] = val//merge(originalRuleObj[field][_key], val, true);\n // //} //else {\n // // originalRuleObj[field] = merge(originalRuleObj[field], val, true);\n // //}\n \n // } else if ( typeof(originalRuleObj[_key]) != 'undefined' ) {\n // originalRuleObj[_key] = val\n // //originalRuleObj[_key] = merge(originalRuleObj[_key], val, true)\n // }\n \n \n } //else if ( typeof(originalRuleObj[nextFieldName]) != 'undefined' ) {\n // field = nextFieldName;\n //}\n \n keys.splice(0,1);\n if (nextFieldName == _id) {\n rulesFromPath(obj[ _id ], keys, val, originalRuleObj, nextFieldName, i, len)\n } else if ( typeof(obj[ _id ]) != 'undefined' ) {\n rulesFromPath(obj[ _id ], keys, val, originalRuleObj, nextFieldName, i, len)\n } else {\n rulesFromPath(obj, keys, val, originalRuleObj, field, i, len)\n }\n \n }\n \n for (var prop in instance.rules) {\n if ( prop != ruleName && re.test(prop) ) {\n \n propName = prop.replace(propRe, '');\n if ( /\\./.test(propName) ) {\n var keys = propName.split(/\\./g);\n rulesFromPath( ruleObj, keys, instance.rules[prop], ruleObj, '', 0, ruleObj.count()-1 )\n } \n }\n }\n //cache rules\n local.rules[ruleName] = ruleObj;\n return ruleObj\n }\n \n var makeObjectFromArgs = function(root, args, obj, len, i, value, rootObj) {\n \n if (i == len) { // end\n eval(root +'=value');\n return rootObj\n }\n \n var key = args[i].replace(/^\\[|\\]$/g, '');\n\n // init root object\n if ( typeof(rootObj) == 'undefined' ) {\n \n rootObj = {};\n root = 'rootObj';\n \n root += (/^\\d+$/.test(key)) ? '['+ key + ']' : '[\"'+ key +'\"]';\n eval(root +'=obj'); \n } else {\n root += (/^\\d+$/.test(key)) ? '['+ key + ']' : '[\"'+ key +'\"]';\n }\n \n\n var nextKey = ( typeof(args[i + 1]) != 'undefined' ) ? args[i + 1].replace(/^\\[|\\]$/g, '') : null;\n var valueType = ( nextKey && parseInt(nextKey) == nextKey ) ? [] : {}\n if ( nextKey ) { \n eval(root +' = valueType');\n }\n \n if ( typeof(obj[key]) == 'undefined' ) {\n\n if (/^\\d+$/.test(nextKey)) { // collection index ?\n obj[key] = [];\n } else {\n obj[key] = {};\n }\n\n ++i;\n return makeObjectFromArgs(root, args, obj[key], len, i, value, rootObj);\n }\n \n ++i;\n return makeObjectFromArgs(root, args, obj[key], len, i, value, rootObj);\n }\n\n \n\n /**\n * makeObject - Preparing form data\n *\n * @param {object} obj - data\n * @param {string\\number\\boolean} value\n * @param {array} string\n * @param {number} len\n * @param {number} i\n *\n * */\n var makeObject = function (obj, value, args, len, i) {\n\n if (i >= len) {\n return false\n }\n\n var key = args[i].replace(/^\\[|\\]$/g, '');\n var nextKey = ( i < len-1 && typeof(args[i+1]) != 'undefined' ) ? args[i+1].replace(/^\\[|\\]$/g, '') : null;\n \n if ( typeof(obj[key]) == 'undefined' ) {\n if (nextKey && /^\\d+$/.test(nextKey)) {\n nextKey = parseInt(nextKey);\n obj[key] = []\n } else {\n obj[key] = {}\n }\n }\n\n var tmpObj = null;\n if ( Array.isArray(obj[key]) ) {\n //makeObjectFromArgs(obj[key], args, obj[key], args.length, 1, value);\n tmpObj = makeObjectFromArgs(key, args, obj[key], args.length, 1, value);\n obj[key] = merge(obj[key], tmpObj);\n makeObject(obj[key], value, args, len, i + 1);\n } else {\n if (i == len - 1) {\n obj[key] = value;\n }// else {\n makeObject(obj[key], value, args, len, i + 1)\n //}\n }\n }\n\n var formatData = function (data) {\n\n var args = null\n , obj = {}\n , key = null\n , fields = {}\n , altName = null\n ;\n\n var makeFields = function(fields, isObject, data, len, i) {\n if (i == len ) { // exit\n return fields\n }\n \n var name = (isObject) ? Object.keys(data)[i] : i;\n \n if ( /\\[(.*)\\]/.test(name) ) {\n // backup name key\n key = name;\n // properties\n args = name.match(/(\\[[-_\\[a-z 0-9]*\\]\\]|\\[[-_\\[a-z 0-9]*\\])/ig);\n // root\n name = name.match(/^[-_a-z 0-9]+\\[{0}/ig);\n //altName = name.replace(/.*\\[(.+)\\]$/, \"$1\");\n \n if ( typeof(fields[name]) == 'undefined' ) {\n fields[name] = ( Array.isArray(data[key]) ) ? [] : {};\n }\n // building object tree\n makeObject(obj, data[key], args, args.length, 0);\n \n fields[name] = merge(fields[name], obj);\n obj = {};\n \n } else { // normal case\n fields[name] = data[name];\n }\n name = null;\n altName = null;\n \n ++i;\n return makeFields(fields, isObject, data, len, i); \n }\n \n var len = ( typeof(data) == 'undefined' ) ? 0 : 1;// by default\n var isObject = false;\n if (Array.isArray(data)) {\n len = data.length;\n } else if ( typeof(data) == 'object' ) {\n len = data.count();\n isObject = true;\n } \n \n return makeFields(fields, isObject, data, len, 0);\n //return fields\n }\n \n var checkForDuplicateForm = function(id) {\n // check for duplicate form ids\n var $allForms = document.getElementsByTagName('form');\n var dID = null, duplicateFound = {};\n for (var d = 0, dLen = $allForms.length; d < dLen; ++d) {\n dID = $allForms[d].getAttribute('id') || null; \n if ( typeof(duplicateFound[dID]) == 'undefined' ) {\n duplicateFound[dID] = true;\n } else {\n if ( typeof(instance.$forms[dID]) != 'undefined' && !instance.$forms[dID].warned) {\n if (gina.popinIsBinded) {\n console.warn('Popin/Validator::bindForm($target, customRule): `'+ dID +'` is a duplicate form ID. If not fixed, this could lead to an undesirable behaviour.\\n Check inside your popin content'); \n } else {\n console.warn('Validator::bindForm($target, customRule): `'+ dID +'` is a duplicate form ID. If not fixed, this could lead to an undesirable behaviour.');\n }\n instance.$forms[dID].warned = true;\n } \n }\n }\n }\n \n \n var setObserver = function ($el) {\n var $formInstance = instance.$forms[$el.form.getAttribute('id')];\n var isDisabled = ( /^true$/i.test($el.disabled) ) ? true : false;\n if ( \n isDisabled\n && typeof($formInstance.rule) != 'undefined' \n && typeof($formInstance.rule[$el.name]) != 'undefined'\n && typeof($formInstance.rule[$el.name].exclude) != 'undefined'\n && /^false$/i.test($formInstance.rule[$el.name].exclude)\n ) {\n isDisabled = false;\n }\n // var allowedTypes = allowedLiveInputTypes.slice();\n if (!/^(radio|text|hidden|password|number|date|email)$/i.test($el.type) || isDisabled) {\n return;\n }\n \n // Credits to `Maciej Swist` @https://stackoverflow.com/questions/42427606/event-when-input-value-is-changed-by-javascript\n var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, \"value\");\n var inputSetter = descriptor.set;\n\n //Then modify the \"setter\" of the value to notify when the value is changed:\n descriptor.set = function(val) {\n \n //changing to native setter to prevent the loop while setting the value\n Object.defineProperty(this, 'value', {set:inputSetter});\n \n var _evt = 'change.' + this.id;\n if ( val === this.value && val === this.defaultValue) {\n Object.defineProperty(this, 'value', descriptor);\n return;\n }\n if ( val === this.value) {\n //changing back to custom setter\n Object.defineProperty(this, 'value', descriptor);\n return;\n }\n \n this.value = val;\n // if (document.getElementById(this.id).value !== this.value) {\n // document.getElementById(this.id).value = this.value;\n // }\n\n //Custom code triggered when $el.value is set\n console.debug('Value set: '+val);\n \n if ( typeof(gina.events[_evt]) != 'undefined' ) {\n console.debug('trigger event on: ', this.name, _evt);\n triggerEvent(gina, this, _evt, val);\n }\n //changing back to custom setter\n Object.defineProperty(this, 'value', descriptor);\n }\n \n //Last add the new \"value\" descriptor to the $el element\n Object.defineProperty($el, 'value', descriptor);\n }\n \n var addLiveForInput = function($form, $el, liveCheckTimer, isOtherTagAllowed) {\n \n if (typeof(isOtherTagAllowed) == 'undefined' ) {\n isOtherTagAllowed = false;\n }\n var rules = $form.rules;\n var $formInstance = instance.$forms[$el.form.getAttribute('id')];\n var isDisabled = ( /^true$/i.test($el.disabled) ) ? true : false;\n if ( \n isDisabled\n && typeof($formInstance.rule) != 'undefined' \n && typeof($formInstance.rule[$el.name]) != 'undefined'\n && typeof($formInstance.rule[$el.name].exclude) != 'undefined'\n && /^false$/i.test($formInstance.rule[$el.name].exclude)\n ) {\n isDisabled = false;\n }\n // allowedLiveInputTypes\n if ( /^(radio|checkbox|text|hidden|password|number|date|email)$/i.test($el.type) && !isDisabled || isOtherTagAllowed && !isDisabled ) {\n var field = $el.name;\n var localRule = rules[field] || null;\n if ( !localRule ) {\n checkForRuleAlias(rules, $el);\n \n if ( typeof(rules[field]) == 'undefined' )\n return;\n }\n // data-gina-form-live-check-enabled\n // with local rule \n if ( $form.target.dataset.ginaFormLiveCheckEnabled && localRule) {\n \n var eventsList = [], _evt = null, _e = 0; \n if ( !/^(radio|checkbox)$/i.test($el.type) ) {\n addEventListener(gina, $el, 'focusout.'+$el.id, function(event) {\n event.preventDefault();\n clearTimeout(liveCheckTimer);\n });\n \n // BO Livecheck local events\n _evt = 'change.'+$el.id;\n if ( typeof(gina.events[_evt]) == 'undefined' ) {\n eventsList[_e] = _evt;\n ++_e;\n }\n \n _evt = 'keyup.'+$el.id;\n if ( typeof(gina.events[_evt]) == 'undefined' ) {\n eventsList[_e] = _evt;\n ++_e;\n }\n _evt = 'focusin.'+$el.id;\n if ( typeof(gina.events[_evt]) == 'undefined' ) {\n eventsList[_e] = _evt;\n ++_e;\n }\n _evt = 'focusout.'+$el.id;\n if ( typeof(gina.events[_evt]) == 'undefined' ) {\n eventsList[_e] = _evt;\n ++_e;\n }\n // EO Livecheck local events\n } else {\n if ( /^(radio|checkbox)$/i.test($el.type) ) {\n _evt = 'changed.'+$el.id;\n } else {\n _evt = 'change.'+$el.id;\n }\n \n if ( typeof(gina.events[_evt]) == 'undefined' ) {\n eventsList[_e] = _evt;\n ++_e;\n }\n }\n \n if (eventsList.length > 0) {\n var once = false;\n addListener(gina, $el, eventsList, function(event) { \n event.preventDefault(); \n clearTimeout(liveCheckTimer); \n if ( !once && /^changed\\./i.test(event.type) || !once && /^(radio|checkbox)$/i.test(event.target.type) ) {\n once = true;\n } else if (once && /^changed\\./i.test(event.type) || once && /^(radio|checkbox)$/i.test(event.target.type) ) { \n return false;\n }\n \n if ( \n typeof(instance.$forms[event.target.form.getAttribute('id')].isSubmitting) != 'undefined'\n && /true/i.test(instance.$forms[event.target.form.getAttribute('id')].isSubmitting)\n ) {\n return false;\n }\n \n var processEvent = function() {\n \n console.debug('processing: ' + event.target.name+ '/'+ event.target.id);\n \n // Do not validate `onChange` if `input value` === `orignal value`\n // Or else, you will get an endless loop\n if (\n // ignoring checkbox & radio because value for both have already changed\n !/^(radio|checkbox)$/i.test(event.target.type) \n && event.target.value === event.target.defaultValue\n && event.target.value != ''\n ) {\n //resetting error display\n var errors = instance.$forms[event.target.form.getAttribute('id')].errors;\n if (!errors || errors.count() == 0) {\n handleErrorsDisplay(event.target.form, {}, null, event.target.name);\n return cancelEvent(event);\n } else {\n handleErrorsDisplay(event.target.form, errors, null, event.target.name);\n }\n //return cancelEvent(event);\n }\n \n \n var localField = {}, $localField = {};\n localField[event.target.name] = event.target.value;\n $localField[event.target.name] = event.target;\n \n instance.$forms[event.target.form.getAttribute('id')].isValidating = true;\n validate(event.target, localField, $localField, $form.rules, function onLiveValidation(result){\n instance.$forms[event.target.form.getAttribute('id')].isValidating = false;\n //console.debug('validation on processEvent(...) ', result);\n \n var isFormValid = result.isValid();\n //console.debug('onSilentPreGlobalLiveValidation: '+ isFormValid, result);\n if (isFormValid) {\n //resetting error display\n handleErrorsDisplay(event.target.form, {}, result.data, event.target.name);\n } else { \n handleErrorsDisplay(event.target.form, result.error, result.data, event.target.name);\n }\n //updateSubmitTriggerState( event.target.form, isFormValid );\n // data-gina-form-required-before-submit\n //console.debug('====>', result.isValid(), result);\n \n // Global check required: on all fields\n var $gForm = event.target.form, gFields = null, $gFields = null, gRules = null;\n var gValidatorInfos = getFormValidationInfos($gForm, rules);\n gFields = gValidatorInfos.fields;\n $gFields = gValidatorInfos.$fields;\n var formId = $gForm.getAttribute('id');\n gRules = instance.$forms[formId].rules;\n // Don't be tempted to revome fields that has already been validated\n instance.$forms[formId].isValidating = true;\n validate($gForm, gFields, $gFields, gRules, function onSilentGlobalLiveValidation(gResult){\n instance.$forms[formId].isValidating = false;\n console.debug('['+ formId +'] onSilentGlobalLiveValidation: '+ gResult.isValid(), gResult);\n var isFormValid = gResult.isValid();\n if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) {\n // update toolbar\n if (!gina.forms.errors)\n gina.forms.errors = {};\n \n var objCallback = {\n id : formId,\n errors : gResult.error || {}\n };\n \n window.ginaToolbar.update('forms', objCallback);\n } \n \n \n updateSubmitTriggerState( $gForm, isFormValid);\n \n once = false;\n })\n \n });\n \n \n return;\n }\n \n // radio & checkbox only\n if ( \n /^changed\\./i.test(event.type) \n || \n /^change\\./i.test(event.type) \n && event.target.type == 'radio'\n ) {\n var i = 0;\n return function(once, i) {\n if (i > 0) return;\n ++i;\n return setTimeout(() => {\n console.debug(' changed .... '+$el.id);\n processEvent();\n }, 0); \n \n }(once, i)\n \n }\n // other inputs & textareas\n else if ( /^focusin\\./i.test(event.type) ) {\n if ( /\\-error/.test($el.parentNode.className) ) {\n console.debug('#1 you just focusin ....'+$el.id, $el.value);\n refreshWarning($el);\n }\n }\n else if ( /^focusout\\./i.test(event.type) ) {\n if ( /\\-warning/.test($el.parentNode.className) ) {\n console.debug('#1 you just focusout ....'+$el.id, $el.value); \n refreshWarning($el);\n // in case error context is changed by another task\n handleErrorsDisplay($el.form, instance.$forms[ $el.form.getAttribute('id') ].errors, null, $el.name);\n }\n }\n else if ( /^keyup\\./i.test(event.type) ) {\n $el.ginaFormValidatorTestedValue = $el.value;\n liveCheckTimer = setTimeout( function onLiveCheckTimer() {\n // do not trigger for copy/paste event\n if ( ['91', '17'].indexOf(''+event.keyCode) > -1 && keyboardMapping.count() == 0) {\n //console.debug('mapping ', keyboardMapping);\n return;\n }\n console.debug(' keyup ('+ event.keyCode +') .... '+$el.id, $el.value, ' VS ',$el.ginaFormValidatorTestedValue + '(old)');\n processEvent();\n }, 1000); \n } \n else if (/^change\\./i.test(event.type) && !/^(checkbox)$/i.test(event.target.type) ) {\n console.debug(' change .... '+$el.id);\n processEvent();\n } \n });\n }\n }\n }\n return;\n }\n \n \n \n var setSelectionRange = function($el, selectionStart, selectionEnd) {\n if ($el.setSelectionRange) {\n $el.focus();\n $el.setSelectionRange(selectionStart, selectionEnd);\n }\n else if ($el.createTextRange) {\n var range = $el.createTextRange();\n range.collapse(true);\n range.moveEnd ('character', selectionEnd );\n range.moveStart('character', selectionStart);\n range.select();\n }\n }\n /**\n * setCaretToPos\n * If called after change of `readonly`, use `$el.blur()` before the call\n * \n * @param {object} $el - HTMLElement\n * @param {number} pos \n */\n var setCaretToPos = function ($el, pos) {\n setSelectionRange($el, pos, pos);\n }\n \n var isElementVisible = function($el) {\n return ($el.offsetWidth > 0 || $el.offsetHeight > 0 || $el === document.activeElement) ? true : false;\n }\n \n var focusNextElement = function($el, isGoingBackward) {\n // Add all elements we want to include in our selection\n // Checkboxes and radios are just ignored: like for the default behavior\n var focussableElements = 'a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), select:not([disabled]), [tabindex]:not([disabled]):not([tabindex=\"-1\"])';\n if (document.activeElement && document.activeElement.form) {\n var focussable = Array.prototype.filter.call(document.activeElement.form.querySelectorAll(focussableElements),\n function (element) {\n //Check for visibility while always include the current activeElement \n return element.offsetWidth > 0 || element.offsetHeight > 0 || element === document.activeElement\n });\n var index = focussable.indexOf(document.activeElement);\n if(index > -1) {\n var direcion = focussable[index + 1]; // By default, going forward\n if (isGoingBackward) {\n direcion = focussable[index - 1]\n }\n var nextElement = direcion || focussable[0];\n nextElement.focus();\n } \n }\n }\n /**\n * handleAutoComplete\n * This is a temporary fix to handle safari autocomplete/autosuggest\n * Will be removed when Safari honores autocomplete=\"off\" \n * @param {object} $el HTMLElement\n */\n var handleAutoComplete = function($el, liveCheckTimer) {\n $el.setAttribute('readonly', 'readonly');\n addListener(gina, $el, 'focusout.'+ $el.id, function(event) {\n event.preventDefault();\n clearTimeout(liveCheckTimer);\n \n var $_el = event.currentTarget;\n triggerEvent(gina, $_el, 'change.'+ $_el.id);\n $_el.setAttribute('readonly', 'readonly');\n });\n addListener(gina, $el, 'focusin.'+ $el.id, function(event) {\n event.preventDefault();\n event.currentTarget.removeAttribute('readonly'); \n \n var evtName = 'keydown.'+ event.currentTarget.id;\n // add once\n if ( typeof(gina.events[evtName]) == 'undefined' ) {\n addListener(gina, event.currentTarget, evtName, function(e) {\n e.preventDefault();\n clearTimeout(liveCheckTimer);\n \n var $_el = e.currentTarget; \n var str = e.currentTarget.value;\n var posStart = $_el.selectionStart, posEnd = $_el.selectionEnd;\n $_el.removeAttribute('readonly');\n //console.debug('pressed: '+ e.key+'('+ e.keyCode+')', ' S:'+posStart, ' E:'+posEnd, ' MAP: '+ JSON.stringify(keyboardMapping));\n switch (e.keyCode) {\n case 46: //Delete\n case 8: //Backspace\n if (posStart != posEnd) {\n $_el.value = str.substr(0, posStart) + str.substr(posEnd);\n if (posStart == 0) {\n $_el.value = str.substr(posEnd);\n }\n } else if (posStart == 0) {\n $_el.value = str.substring(posStart+1);\n } else {\n $_el.value = str.substr(0, posStart-1) + str.substr(posEnd);\n }\n \n e.currentTarget.setAttribute('readonly', 'readonly'); \n setTimeout(() => {\n $_el.removeAttribute('readonly'); \n setTimeout(() => {\n if (posStart != posEnd) {\n setCaretToPos($_el, posStart);\n } else if (posStart == 0) {\n setCaretToPos($_el, posStart);\n } else {\n setCaretToPos($_el, posStart-1);\n }\n }, 0)\n \n }, 0);\n break;\n case 9: // Tab\n if (keyboardMapping[16] && keyboardMapping[9]) {\n focusNextElement($_el, true);\n } else {\n focusNextElement($_el);\n } \n break;\n case 13: // Enter \n case 16: // Shift\n break;\n case 37: // ArrowLeft\n console.debug('moving left ', posStart-1);\n setCaretToPos($_el, posStart-1); \n break;\n case 39: // ArrowRight\n if (posStart+1 < str.length+1) {\n setCaretToPos($_el, posStart+1);\n } \n break;\n // Shortcuts\n case 17: //CTRL\n case 91: //CMD\n console.debug(\"CMD hit\");\n e.preventDefault();\n break;\n case 67: // to handle CMD+C (copy)\n if (\n keyboardMapping[67] && keyboardMapping[91] // mac osx\n ||\n keyboardMapping[67] && keyboardMapping[17] // windows\n ) {\n $_el.setSelectionRange(posStart, posEnd);\n document.execCommand(\"copy\");\n break;\n }\n case 86: // to handle CMD+V (paste)\n if (\n keyboardMapping[86] && keyboardMapping[91] // mac osx\n ||\n keyboardMapping[86] && keyboardMapping[17] // windows\n ) {\n if (posStart != posEnd) {\n $_el.value = $_el.value.replace(str.substring(posStart, posEnd), '');\n }\n setCaretToPos($_el, posStart);\n document.execCommand(\"paste\");\n break;\n }\n case 88: // to handle CMD+X (cut)\n if (\n keyboardMapping[88] && keyboardMapping[91] // mac osx\n ||\n keyboardMapping[88] && keyboardMapping[17] // windows\n ) {\n $_el.setSelectionRange(posStart, posEnd);\n document.execCommand(\"cut\");\n break;\n }\n case 90: // to handle CMD+Z (undo)\n if (\n keyboardMapping[90] && keyboardMapping[91] // mac osx\n ||\n keyboardMapping[90] && keyboardMapping[17] // windows\n ) {\n $_el.value = $_el.defaultValue;\n break;\n }\n default:\n // Replace selection\n if (posStart != posEnd) {\n $_el.value = str.substr(0, posStart) + e.key;\n if (posEnd-1 < str.length) {\n $_el.value += str.substring(posEnd)\n }\n } else if (posStart == 0) {\n $_el.value = e.key + str.substring(posStart);\n } else {\n $_el.value = str.substr(0, posStart) + e.key + str.substr(posEnd);\n }\n e.currentTarget.setAttribute('readonly', 'readonly');\n // Force restore last caret position\n setTimeout(() => {\n $_el.removeAttribute('readonly');\n setTimeout(() => {\n setCaretToPos($_el, posStart+1);\n }, 0);\n \n }, 0);\n break;\n } //EO Switch\n });\n }\n \n });\n }\n \n var registerForLiveChecking = function($form, $el) {\n // Filter supported elements\n if ( \n !/^(input|textarea)$/i.test($el.tagName)\n ||\n typeof(gina.events['registered.' + $el.id]) != 'undefined'\n ) {\n return\n }\n // Mutation obeserver - all but type == files\n if ( !/^file$/i.test($el.type) ) {\n setObserver($el);\n } \n var liveCheckTimer = null\n switch ($el.tagName.toLowerCase()) {\n \n case 'textarea':\n addLiveForInput($form, $el, liveCheckTimer, true);\n break;\n default:\n addLiveForInput($form, $el, liveCheckTimer);\n // Bypass Safari autocomplete\n var isAutoCompleteField = $el.getAttribute('autocomplete');\n if (\n /safari/i.test(navigator.userAgent)\n && isAutoCompleteField\n && /^(off|false)/i.test(isAutoCompleteField) \n ) {\n handleAutoComplete($el, liveCheckTimer)\n }\n break;\n }\n gina.events['registered.' + $el.id] = $el.id;\n }\n \n /**\n * bindUploadResetOrDeleteTrigger\n * \n * @param {string} bindingType - `reset`or `delete`\n * @param {object} $uploadTrigger - HTMLFormElement\n * @param {number} index\n * \n */\n var bindUploadResetOrDeleteTrigger = function(bindingType, $uploadTrigger, index) {\n \n // Binding upload reset or delete trigger\n // var $currentForm = $uploadTrigger.form;\n // for (let i = 0, len = $currentForm.length; )\n // trigger is by default you {input.id} + '-delete-trigger' \n // e.g.: <input type=\"file\" id=\"my-upload\" name=\"my-upload\">\n // => <a href=\"/path/to/tmpfile/delete-action\" id=\"my-upload-delete-trigger\">Remove</a>\n // But you can use atrtibute `data-gina-form-upload-delete-trigger` to override it \n var uploadResetOrDeleteTriggerId = $uploadTrigger.id + '-' +index+ '-'+bindingType+'-trigger';\n var $uploadResetOrDeleteTrigger = document.getElementById(uploadResetOrDeleteTriggerId); \n if (!$uploadResetOrDeleteTrigger) {\n uploadResetOrDeleteTriggerId = $uploadTrigger.getAttribute('data-gina-form-upload-'+ '-' +index+ +bindingType+'-trigger');\n $uploadResetOrDeleteTrigger = document.getElementById(uploadResetOrDeleteTriggerId);\n }\n \n if ( \n $uploadResetOrDeleteTrigger \n && typeof($uploadResetOrDeleteTrigger.isBinded) == 'undefined' \n || \n $uploadResetOrDeleteTrigger \n && typeof($uploadResetOrDeleteTrigger.isBinded) != 'undefined' \n && !/true/i.test($uploadResetOrDeleteTrigger.isBinded) \n ) { \n addListener(gina, $uploadResetOrDeleteTrigger, 'click', function onUploadResetOrDeleteTriggerClick(e) {\n e.preventDefault();\n \n onUploadResetOrDelete($uploadTrigger, bindingType);\n });\n $uploadResetOrDeleteTrigger.isBinded = true;\n } else {\n console.warn('[FormValidator::bindForm][upload]['+$uploadTrigger.id+'] : did not find `upload '+bindingType+' trigger`.\\nPlease, make sure that your delete element ID is `'+ uploadResetOrDeleteTriggerId +'-'+bindingType+'-trigger`, or add to your file input ('+ $uploadTrigger.id +') -> `data-gina-form-upload-'+bindingType+'-trigger=\"your-custom-id\"` definition.');\n }\n }\n \n var checkUploadUrlActions = function($el, $errorContainer) {\n \n var checkAction = function($el, action, $errorContainer) {\n var defaultRoute = null;\n switch (action) {\n case 'data-gina-form-upload-action':\n defaultRoute = 'upload-to-tmp-xml';\n break;\n case 'data-gina-form-upload-reset-action':\n defaultRoute = 'upload-delete-from-tmp-xml';\n break;\n }\n var uploadActionUrl = $el.getAttribute(action);\n if (!uploadActionUrl || uploadActionUrl == '' ) {\n if (!defaultRoute)\n console.warn('`'+ action +'` definition not found for `'+ $el.id + '`. Trying to get default route.');\n var additionalErrorDetails = null;\n try {\n if (defaultRoute)\n uploadActionUrl = routing.getRoute(defaultRoute);\n } catch (err) {\n additionalErrorDetails = err;\n }\n \n if (uploadActionUrl) {\n console.info('Ignore previous warnings regarding upload. I have found a default `'+action+'` route: `'+ defaultRoute +'@'+ uploadActionUrl.bundle +'`');\n $el.setAttribute('data-gina-form-upload-action', uploadActionUrl.toUrl());\n } else {\n var errMsg = '`'+ action +'` needs to be defined to proceed for your `input[type=file]` with ID `'+ $el.id +'`\\n'+ additionalErrorDetails +'\\n';\n if ($errorContainer) {\n $errorContainer.innerHTML += errMsg.replace(/(\\n|\\r)/g, '<br>');\n }\n console.error(errMsg);\n } \n }\n }\n // checking upload-action\n checkAction($el, 'data-gina-form-upload-action', $errorContainer);\n // checking upload-reset-action\n checkAction($el, 'data-gina-form-upload-reset-action', $errorContainer);\n // checking upload-delete-action\n checkAction($el, 'data-gina-form-upload-delete-action', $errorContainer);\n }\n \n /**\n * reBindForm - This is a WIP\n * \n * @param {object} HTMLElement\n * @param {object} rules\n * @return {object} formValidatorInstance\n */\n var reBindForm = function($target, rules, cb) {\n // Unbind form\n var formInstance = unbindForm($target);\n // reset errors\n //resetErrorsDisplay(formInstance.id); \n // Bind\n bindForm(formInstance.target, rules);\n \n if ( cb ) {\n return cb(formInstance); \n }\n return formInstance;\n }\n \n var unbindForm = function($target) {\n var $form = null\n , _id = null\n ;\n\n try {\n if ( $target.getAttribute && $target.getAttribute('id') ) {\n _id = $target.getAttribute('id');\n if ( typeof(instance.$forms[_id]) != 'undefined')\n $form = instance.$forms[_id];\n else\n throw new Error('form instance `'+ _id +'` not found');\n\n } else if ( typeof($target.target) != 'undefined' ) {\n $form = $target;\n _id = $form.id;\n } else {\n throw new Error('Validator::unbindForm($target): `$target` must be a DOM element\\n'+err.stack )\n }\n } catch(err) {\n throw new Error('Validator::unbindForm($target) could not unbind form `'+ $target +'`\\n'+err.stack )\n }\n \n // No need to unbind if not binded\n if ( typeof($form) != 'undefined' && !$form.binded) {\n return $form\n }\n \n // form events\n removeListener(gina, $form, 'success.' + _id);\n removeListener(gina, $form, 'error.' + _id);\n\n if ($form.target.getAttribute('data-gina-form-event-on-submit-success'))\n removeListener(gina, $form, 'success.' + _id + '.hform');\n \n if ($form.target.getAttribute('data-gina-form-event-on-submit-error'))\n removeListener(gina, $form, 'error.' + _id + '.hform');\n\n removeListener(gina, $form, 'validate.' + _id);\n removeListener(gina, $form, 'validated.' + _id);\n removeListener(gina, $form, 'submit.' + _id);\n removeListener(gina, $form, 'reset.' + _id);\n \n \n\n // binded elements\n var $el = null\n //, evt = null\n , $els = []\n , $elTMP = [];\n\n // submit buttons\n $elTMP = $form.target.getElementsByTagName('button');\n if ( $elTMP.length > 0 ) {\n for(let i = 0, len = $elTMP.length; i < len; ++i) {\n // if button is != type=\"submit\", you will need to provide : data-gina-form-submit\n // TODO - On button binding, you can then provide data-gina-form-action & data-gina-form-method\n $els.push($elTMP[i])\n }\n }\n\n // submit links\n $elTMP = $form.target.getElementsByTagName('a');\n if ( $elTMP.length > 0 ) {\n for(let i = 0, len = $elTMP.length; i < len; ++i) {\n $els.push($elTMP[i])\n }\n }\n\n // checkbox, radio, file, text, number, hidden, date .. ALL BUT hidden\n $elTMP = $form.target.getElementsByTagName('input');\n if ( $elTMP.length > 0 ) {\n for (let i = 0, len = $elTMP.length; i < len; ++i) {\n \n if ( !/^(hidden)$/i.test($elTMP[i].type) )\n $els.push( $elTMP[i] );\n \n \n if (/^(file)$/i.test($elTMP[i].type)) {\n // special case\n // vForm has to be handle here, it does not exist in the document context\n let vFormId = $elTMP[i].getAttribute('data-gina-form-virtual');\n if ( vFormId ) {\n let $vForm = getFormById(vFormId).target;\n if ($vForm) {\n $els.push( $vForm );\n // `events` is defined on top of this file\n // It is the list of allowed events\n for (let e = 0, eLen = events.length; e < eLen; e++) {\n let evt = events[e];\n if ( typeof(gina.events[ evt +'.'+ vFormId + '.hform' ]) != 'undefined' && gina.events[ evt +'.'+ vFormId + '.hform' ] == vFormId ) { \n removeListener(gina, $vForm, evt +'.'+ vFormId + '.hform')\n } \n } \n }\n }\n } else { // other types\n // `events` is defined on top of this file\n // It is the list of allowed events\n for (let e = 0, eLen = events.length; e < eLen; e++) {\n let evt = events[e] +'.'+ $elTMP[i].id;\n if ( typeof(gina.events[ evt ]) != 'undefined' && gina.events[ evt ] == $elTMP[i].id ) { \n removeListener(gina, $elTMP[i], evt);\n }\n evt = events[e];\n if ( typeof(gina.events[ evt ]) != 'undefined' && gina.events[ evt ] == $elTMP[i].id ) { \n removeListener(gina, $elTMP[i], evt);\n }\n evt = $elTMP[i].id;\n if ( typeof(gina.events[ evt ]) != 'undefined' && gina.events[ evt ] == $elTMP[i].id ) { \n removeListener(gina, $elTMP[i], evt);\n }\n }\n }\n }\n }\n \n // textarea\n $elTMP = $form.target.getElementsByTagName('textarea');\n if ( $elTMP.length > 0 ) {\n for(let i = 0, len = $elTMP.length; i < len; ++i) {\n $els.push( $elTMP[i] )\n }\n }\n \n \n // forms inside main form\n $elTMP = $form.target.getElementsByTagName('form');\n if ( $elTMP.length > 0 ) {\n for(let i = 0, len = $elTMP.length; i < len; ++i) {\n $els.push( $elTMP[i] )\n }\n }\n // main form\n $els.push( $form.target );\n for (let i = 0, len = $els.length; i < len; ++i) {\n\n $el = $els[i];\n let eId = $el.getAttribute('id');\n for (let e = 0, eLen = events.length; e < eLen; e++) {\n let evt = events[e];\n let eventName = evt; \n // remove proxy\n // if ( typeof(gina.events[ evt ]) != 'undefined' ) { \n // removeListener(gina, $el, evt);\n // } \n \n if ( typeof(gina.events[ eventName ]) != 'undefined' && gina.events[ eventName ] == eId ) { \n removeListener(gina, $el, eventName);\n }\n \n // eventName = evt +'._case_'+ $el.name;\n // if ( typeof(gina.events[ eventName ]) != 'undefined') { \n // removeListener(gina, $el, eventName);\n // } \n \n eventName = eId;\n if ( typeof(gina.events[ eventName ]) != 'undefined' && gina.events[ eventName ] == eId ) { \n removeListener(gina, $el, eventName);\n }\n \n eventName = evt +'.'+ eId;\n if ( typeof(gina.events[ eventName ]) != 'undefined' && gina.events[ eventName ] == eId ) { \n removeListener(gina, $el, eventName);\n }\n \n eventName = evt +'.'+ eId;\n if ( typeof(gina.events[ eventName ]) != 'undefined' && gina.events[ eventName ] == eventName ) { \n removeListener(gina, $el, eventName);\n }\n \n eventName = evt +'.'+ eId + '.hform';\n if ( typeof(gina.events[ eventName ]) != 'undefined' && gina.events[ eventName ] == eId ) { \n removeListener(gina, $el, eventName);\n }\n }// EO for events\n } //EO for $els\n \n $els = null; $el = null; $elTMP = null; evt = null;\n // reset error display\n //resetErrorsDisplay($form);\n // or\n // $form.target.dataset.ginaFormIsResetting = true;\n // handleErrorsDisplay($form.target, {});\n $form.binded = false;\n \n return $form;\n }\n \n var checkForRuleAlias = function(formRules, $el) {\n var field = $el.name;\n var localRule = formRules[field] || null;\n if ( !localRule ) {\n // looking for regexp aliases from rules\n for (let _r in formRules) {\n if ( /^\\//.test(_r) ) { // RegExp found\n re = _r.match(/\\/(.*)\\//).pop(); \n flags = _r.replace('/'+ re +'/', '');\n // fix escaping \"[\" & \"]\"\n re = re.replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]');\n re = new RegExp(re, flags);\n if ( re.test(field) ) { \n // create new entry \n localRule = formRules[field] = formRules[_r];\n break;\n } \n } \n }\n }\n }\n\n /**\n * bindForm\n *\n * @param {object} $target - DOM element\n * @param {object} [customRule]\n * */\n var bindForm = function($target, customRule) {\n\n var $form = null\n , _id = null\n , rules = ( typeof(local.rules.count() > 0 ) ) ? local.rules : instance.rules\n ;\n\n try {\n if ( $target.getAttribute && $target.getAttribute('id') ) {\n _id = $target.getAttribute('id');\n if ( typeof(instance.$forms[_id]) != 'undefined')\n $form = instance.$forms[_id];\n else\n throw new Error('form instance `'+ _id +'` not found');\n\n } else {\n throw new Error('Validator::bindForm($target, customRule): `$target` must be a DOM element\\n'+err.stack )\n }\n } catch(err) {\n throw new Error('Validator::bindForm($target, customRule) could not bind form `'+ $target +'`\\n'+err.stack )\n }\n\n if ( typeof($form) != 'undefined' && $form.binded) {\n return false\n }\n \n console.debug('binding for: '+ _id);\n \n \n var withRules = false, rule = null, evt = '', proceed = null;\n\n if ( \n typeof(customRule) != 'undefined' \n || \n typeof(_id) == 'string' \n && typeof(rules[_id.replace(/\\-|\\//g, '.')]) != 'undefined' \n ) {\n withRules = true;\n\n if ( customRule && typeof(customRule) == 'object' ) {\n rule = customRule\n } else if ( \n customRule \n && typeof(customRule) == 'string' \n && typeof(rules[customRule.replace(/\\-|\\//g, '.')]) != 'undefined'\n ) { \n rule = getRuleObjByName(customRule.replace(/\\-|\\//g, '.'))\n } else {\n rule = getRuleObjByName(_id.replace(/\\-|\\//g, '.'))\n }\n\n $form.rules = rule;\n if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) {\n // update toolbar\n if (!gina.forms.rules)\n gina.forms.rules = {};\n\n objCallback = {\n id : _id,\n rules : $form.rules\n };\n\n window.ginaToolbar.update('forms', objCallback);\n }\n } else { // form without any rule binded\n $form.rules = {}\n }\n \n // Live check by default - data-gina-form-live-check-enabled\n if ( \n typeof($form.target.dataset.ginaFormLiveCheckEnabled) == 'undefined'\n && $form.rules.count() > 0\n ) {\n $form.target.dataset.ginaFormLiveCheckEnabled = true;\n } else if( typeof($form.target.dataset.ginaFormLiveCheckEnabled) != 'undefined' ) {\n $form.target.dataset.ginaFormLiveCheckEnabled = ( /^true$/i.test($form.target.dataset.ginaFormLiveCheckEnabled) ) ? true : false;\n } else {\n $form.target.dataset.ginaFormLiveCheckEnabled = false;\n }\n\n // form fields collection\n if (!$form.fieldsSet)\n $form.fieldsSet = {};\n\n // binding form elements\n var type = null\n , id = null\n \n // a|links\n , $a = $target.getElementsByTagName('a')\n // input type: checkbox, radio, hidden, text, files, number, date ...\n , $inputs = $target.getElementsByTagName('input')\n // textarea\n , $textareas = $target.getElementsByTagName('textarea')\n // select\n , $select = $target.getElementsByTagName('select')\n , allFormGroupedElements = {}\n , allFormGroupNames = []\n , formElementGroup = {}\n , formElementGroupTmp = null\n , formElementGroupItems = {}\n // file upload\n , $htmlTarget = null \n , $progress = null\n ;\n \n var elId = null;\n \n // BO Binding a - not needed anymore since popin is binding link before binding child forms\n // for (let f = 0, len = $a.length; f < len; ++f) {\n // let isPopinClick = false, hrefAttr = $a[f].getAttribute('href');\n // if ( !hrefAttr || hrefAttr == '' ) {\n // // Preventing popin auto to redirect to current/host page url\n // $a[f].setAttribute('href', '#');\n // isPopinClick = true;\n // }\n // elId = $a[f].getAttribute('id');\n // if (!elId || elId == '') {\n // elId = 'click.'; // by default\n // if ( $target.isPopinContext ) {\n // elId = ( isPopinClick ) ? 'popin.click.' : 'popin.link.';\n // }\n // elId += uuid.v4();\n // $a[f].setAttribute('id', elId)\n // }\n // }\n // EO Binding a\n \n // BO Binding textarea\n for (let f = 0, len = $textareas.length; f < len; ++f) {\n checkForRuleAlias($form.rules, $textareas[f]);\n elId = $textareas[f].getAttribute('id');\n if (!elId || elId == '') {\n elId = 'textareas.' + uuid.v4();\n $textareas[f].setAttribute('id', elId)\n }\n if (!$form.fieldsSet[ elId ]) {\n let defaultValue = $textareas[f].value || '';\n // // just in case\n // if ( \n // typeof($form.fieldsSet[elId]) != 'undefined'\n // && typeof($form.fieldsSet[elId].defaultValue) != 'undefined'\n // ) {\n // defaultValue = $form.fieldsSet[elId].defaultValue;\n // }\n $form.fieldsSet[elId] = {\n id: elId,\n name: $textareas[f].name || null,\n value: $textareas[f].value || '',\n defaultValue: defaultValue\n }\n }\n // Adding live check\n if (/^true$/i.test($form.target.dataset.ginaFormLiveCheckEnabled) ) {\n registerForLiveChecking($form, $textareas[f]);\n }\n \n }\n // EO Binding textarea\n \n // BO Binding input \n for (let f = 0, len = $inputs.length; f < len; ++f) {\n checkForRuleAlias($form.rules, $inputs[f]);\n elId = $inputs[f].getAttribute('id');\n if (!elId || elId == '') {\n elId = 'input.' + uuid.v4();\n $inputs[f].setAttribute('id', elId)\n }\n\n if (!$form.fieldsSet[ elId ]) {\n let defaultValue = $inputs[f].value;\n if (/$(on|true|false)$/i.test(defaultValue)) {\n defaultValue = (/$(on|true)$/i.test(defaultValue)) ? true : false;\n }\n // just in case\n // if ( \n // typeof($form.fieldsSet[elId]) != 'undefined'\n // && typeof($form.fieldsSet[elId].defaultValue) != 'undefined'\n // ) {\n // defaultValue = $form.fieldsSet[elId].defaultValue;\n // }\n \n $form.fieldsSet[elId] = {\n id: elId,\n name: $inputs[f].name || null,\n value: defaultValue || ( !/^(checkbox|radio)$/i.test($inputs[f].type) ) ? \"\" : $inputs[f].checked,\n defaultValue: ( !/^(checkbox|radio)$/i.test($inputs[f].type) ) ? defaultValue : $inputs[f].checked\n }\n \n if ( /^(checkbox|radio)$/i.test($inputs[f].type) && typeof($form.fieldsSet[elId].defaultChecked) == 'undefined' ) {\n \n \n $form.fieldsSet[elId].defaultChecked = ( \n /^(true|on)$/i.test($inputs[f].checked)\n ||\n /^(true|on)$/.test(defaultValue)\n && /^(checkbox)$/i.test($inputs[f].type) \n ) ? true : false;\n \n if (/^radio$/i.test($inputs[f].type) ) {\n $form.fieldsSet[elId].value = $inputs[f].value;\n $form.fieldsSet[elId].defaultValue = $inputs[f].value;\n }\n }\n }\n \n // Adding live check\n if (/^true$/i.test($form.target.dataset.ginaFormLiveCheckEnabled) ) {\n registerForLiveChecking($form, $inputs[f]);\n }\n \n formElementGroupTmp = $inputs[f].getAttribute('data-gina-form-element-group');\n if (formElementGroupTmp) {\n // recording group names\n if ( allFormGroupNames.indexOf(formElementGroupTmp) < 0 ) {\n allFormGroupNames.push(formElementGroupTmp);\n } \n \n let _name = $inputs[f].getAttribute('name') || elId;\n if (_name === elId) {\n $inputs[f].setAttribute('name', elId)\n }\n allFormGroupedElements[elId] = {\n id : elId,\n name : _name,\n group : formElementGroupTmp,\n target : $inputs[f]\n };\n formElementGroup[ $inputs[f].name ] = new RegExp('^'+formElementGroupTmp.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n // Attention, this means that all dependening field will be\n // ignored on validation, unless you write a rule that\n // will override this behavior or else your fields won't be submited\n // this behaviour only applies to Form Grouped Elements\n if (withRules) {\n if ( typeof($form.rules[ $inputs[f].name ]) == 'undefined') {\n $form.rules[ $inputs[f].name ] = {}\n }\n // By default exclude groups only if not required\n // Those will be included if member of selected group\n // See : handleGroupDependencies() \n if ( \n typeof($form.rules[ $inputs[f].name ].isRequired) == 'undefined'\n || !$form.rules[ $inputs[f].name ].isRequired\n ) {\n $form.rules[ $inputs[f].name ].exclude = true;\n } \n }\n }\n // handling groups dependencies\n if ( formElementGroup.count() > 0 ) {\n var formElementGroupName = null, formElementGroupType = null, formElementIsIgnored = null;\n for ( var g in formElementGroup ) {\n if ($inputs[f].name == g) continue;\n // checkbox group init \n formElementGroupName = $inputs[f].getAttribute('data-gina-form-element-group') || null;\n if ( formElementGroup[g].test($inputs[f].name) ) {\n $inputs[f].disabled = true; // by default \n if ( typeof(formElementGroupItems[ g ]) == 'undefined' ) {\n formElementGroupItems[ g ] = {}\n }\n formElementGroupItems[ g ][ $inputs[f].name ] = $inputs[f];\n }\n \n }\n }\n // Binding upload file\n // todo : data-gina-file-autosend=\"false\" when false, don't trigger the sending to the backend\n // todo : progress bar\n // todo : on('success') -> preview\n if ( /^file$/i.test($inputs[f].type) ) { \n // Binding upload trigger\n // trigger is by default you {input.id} + '-trigger' \n // e.g.: <input type=\"file\" id=\"my-upload\" name=\"my-upload\">\n // => <button type=\"button\" id=\"my-upload-trigger\">Choose a file</button>\n // But you can use atrtibute `data-gina-form-upload-trigger` to override it \n var uploadTriggerId = $inputs[f].getAttribute('data-gina-form-upload-trigger');\n if (!uploadTriggerId)\n uploadTriggerId = $inputs[f].id;\n \n var $upload = null\n , $uploadTrigger = null\n ;\n // `$htmlTarget` cannot be used if you need to add a listner on the searched element\n $htmlTarget = new DOMParser().parseFromString($target.innerHTML, 'text/html');\n if (uploadTriggerId) { \n $uploadTrigger = document.getElementById(uploadTriggerId);\n //$uploadTrigger = $htmlTarget.getElementById(uploadTriggerId);\n }\n var $errorContainer = document.getElementById($inputs[f].id + '-error');\n checkUploadUrlActions($inputs[f], $errorContainer ); \n \n // check default UploadResetOrDeleteTrigger state\n // required to bind delete - look for all delete triggers\n // $deleteTriggers = []; \n // bindUploadResetOrDeleteTrigger(bindingType, $uploadTrigger, index);\n // eg.: document-files-0-preview; if $inputs[f].id === `document-files-0`\n var $previewContainer = $htmlTarget.getElementById(uploadTriggerId + '-preview');\n if ( \n $previewContainer \n && $uploadTrigger\n && !/none/i.test(window.getComputedStyle($previewContainer).display)\n // for safety\n && !/none/i.test($previewContainer.parentElement.style.display)\n ) {\n \n var $deleteLink = null, index = 0, bindingType = 'delete'; \n console.debug('preview is visible ...');\n $uploadTrigger.customFiles = [];\n $uploadTrigger.form = $target;\n var $els = $previewContainer.childNodes;\n for (let i = 0, len = $els.length; i < len; i++) {\n let $img = null;\n if ( /ul/i.test($els[i].tagName) ) {\n for (let e = 0, eLen = $els[i].length; e < eLen; e++) {\n //let $li = new DOMParser().parseFromString($els[i].innerHTML, 'text/html');\n let $li = $$els[i];\n for (let l = 0, lLen = $li.length; l < lLen; l++) {\n if ( /img/i.test($li[l]) ) {\n $img = $li[l];\n $img.setAttribute('');\n \n index++;\n }\n }\n \n } \n } else if ( /img/i.test($els[i].tagName) ) {\n $img = $els[i];\n deleteLinkId = uploadTriggerId + '-'+index+'-delete-trigger';\n let file = $img.src.substr($img.src.lastIndexOf('/')+1);\n $uploadTrigger.customFiles.push({\n name: file,\n deleteLinkId: deleteLinkId\n });\n // bind reset trigger\n bindUploadResetOrDeleteTrigger(bindingType, $uploadTrigger, index);\n \n index++;\n }\n }\n }\n \n // binding upload trigger\n // if ( $uploadTrigger ) {\n // $uploadTrigger.setAttribute('data-gina-form-upload-target', $inputs[f].id);\n // addListener(gina, $uploadTrigger, 'click', function(event) {\n // event.preventDefault();\n // var $el = event.target;\n \n // var fileElemId = $el.getAttribute('data-gina-form-upload-target') || null; \n // if (fileElemId)\n // $upload = document.getElementById(fileElemId);\n \n // if ($upload) {\n // removeListener(gina, $upload, 'click');\n // $upload.value = '';// force reset : != multiple\n // triggerEvent(gina, $upload, 'click', event.detail);\n // } \n // });\n // }\n \n // binding file element == $upload\n // setTimeout(() => {\n // removeListner(gina, $inputs[f], 'change');\n // }, 0); \n addListener(gina, $inputs[f], 'change', function(event) {\n event.preventDefault();\n var $el = event.currentTarget;\n // [0] is for a single file, when multiple == false\n //var files = Array.from($el.files);\n var files = $el.files;\n // used for validation & onUploadResetOrDelete\n $el.customFiles = Array.from(files);\n if (!files.length ) return false;\n \n \n \n \n // $progress = $($(this).parent().find('.progress'));\n var url = $el.getAttribute('data-gina-form-upload-action'); \n var name = $el.getAttribute('name');\n var fileId = name; \n var uploadFormId = 'gina-upload-' + name.replace(/\\[/g, '-').replace(/\\]/g, '-' + $form.id);\n $el.setAttribute('data-gina-form-virtual', uploadFormId);\n var eventOnSuccess = $el.getAttribute('data-gina-form-upload-on-success');\n var eventOnError = $el.getAttribute('data-gina-form-upload-on-error');\n var errorField = null;\n \n if (files.length > 0) {\n \n // create form if not exists \n var $uploadForm = null, $activePopin = null; \n if ( isPopinContext() ) {\n // getting active popin\n $activePopin = gina.popin.getActivePopin();\n $activePopin.$target = new DOMParser().parseFromString($activePopin.target.outerHTML, 'text/html');\n // binding to DOM\n $activePopin.$target.getElementById($activePopin.id).innerHTML = document.getElementById($activePopin.id).innerHTML;\n \n $uploadForm = $activePopin.$target.getElementById(uploadFormId); \n } else {\n $uploadForm = document.getElementById(uploadFormId);\n }\n \n if ( !$uploadForm ) {\n \n $uploadForm = getFormById(uploadFormId);\n if (!$uploadForm) {\n $uploadForm = (isPopinContext()) \n ? $activePopin.$target.createElement('form') \n : document.createElement('form');\n }\n \n\n // adding form attributes\n $uploadForm.id = uploadFormId;\n $uploadForm.action = url;\n $uploadForm.enctype = 'multipart/form-data';\n $uploadForm.method = 'POST';\n \n \n \n if ( typeof($el.form) != 'undefined' ) {\n \n // adding virtual fields\n var fieldPrefix = 'files'; // by default\n var fieldName = $el.getAttribute('data-gina-form-upload-prefix') || $el.name || $el.getAttribute('name');\n var fieldId = $el.id || $el.getAttribute('id');\n \n var hasPreviewContainer = false;\n var previewContainer = $el.getAttribute('data-gina-form-upload-preview') || fieldId + '-preview';\n previewContainer = (isPopinContext())\n ? $activePopin.$target.getElementById(previewContainer)\n : document.getElementById(previewContainer); \n \n if ( typeof(previewContainer) != 'undefined' ) {\n hasPreviewContainer = true; \n }\n \n if (fieldName) {\n fieldPrefix = fieldName\n }\n \n var hiddenFields = []\n , hiddenFieldObject = null \n , mandatoryFields = [\n 'name'\n , 'group'\n , 'originalFilename'\n , 'ext'\n , 'encoding'\n , 'size'\n , 'height' // will be removed depending on the mime type\n , 'width' // will be removed depending on the mime type\n , 'location'\n , 'mime'\n , 'preview'\n ]\n , formInputsFields = $el.form.getElementsByTagName('INPUT')\n , fieldType = null\n , hiddenField = null\n , _userName = null\n , _altId = null\n , _name = null\n , _nameRe = null\n , subPrefix = null\n , uploadFields = {}\n ;\n \n for (var _f = 0, _fLen = files.length; _f < _fLen; ++_f) { // for each file \n // binding upload reset trigger\n bindUploadResetOrDeleteTrigger('reset', $el, _f); \n hiddenFields[_f] = null;\n subPrefix = fieldPrefix + '['+ _f +']';\n _nameRe = new RegExp('^'+subPrefix.replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]'));\n // collecting existing DOM fields\n for (var h = 0, hLen = formInputsFields.length; h < hLen; ++h) {\n fieldType = formInputsFields[h].getAttribute('type');\n hiddenField = null;\n _name = null, _userName = null;\n errorField= formInputsFields[h].getAttribute('data-gina-form-upload-error') || fieldId + '-error' || null;\n \n if (fieldType && /hidden/i.test(fieldType) ) {\n hiddenField = formInputsFields[h];\n \n _name = ( /\\[\\w+\\]$/i.test(hiddenField.name) ) \n ? hiddenField.name.match(/\\[\\w+\\]$/)[0].replace(/\\[|\\]/g, '') \n : hiddenField.name; \n _userName = ( /\\[\\w+\\]$/i.test(hiddenField.name) ) \n ? hiddenField.name.match(/\\[\\w+\\]$/)[0].replace(/\\[|\\]/g, '') \n : hiddenField.name;\n \n // mandatory informations\n if (\n hiddenField \n && typeof(_name) != 'undefiend' \n && mandatoryFields.indexOf( _name ) > -1\n && _nameRe.test( hiddenField.name )\n ) {\n \n if (!hiddenFields[_f] )\n hiddenFields[_f] = {};\n \n if ( /\\[preview\\]/i.test(hiddenField.name) ) {\n if ( typeof(hiddenFields[_f].preview) == 'undefined' )\n hiddenFields[_f].preview = {};\n \n hiddenFields[_f].preview[_name] = hiddenField;\n } else {\n hiddenFields[_f][_name] = hiddenField;\n } \n } else if (\n hiddenField \n && typeof(_name) != 'undefiend' \n && mandatoryFields.indexOf( _name ) < 0\n && _nameRe.test( hiddenField.name )\n ) { // defined by user\n if (!hiddenFields[_f] )\n hiddenFields[_f] = {};\n \n if ( /\\[preview\\]/i.test(hiddenField.name) ) {\n if ( typeof(hiddenFields[_f].preview) == 'undefined' )\n hiddenFields[_f].preview = {};\n \n hiddenFields[_f].preview[_userName] = hiddenField;\n } else {\n hiddenFields[_f][_userName] = hiddenField;\n } \n }\n } \n }\n \n // completing by adding non-declared mandatoring fields in the DOM: all but preview\n for (var m = 0, mLen = mandatoryFields.length; m < mLen; ++m) {\n // optional, must be set by user\n // needs recheck \n if (!hiddenFields[_f] )\n hiddenFields[_f] = {};\n \n if ( typeof(hiddenFields[_f][ mandatoryFields[m] ]) == 'undefined' ) {\n \n _name = fieldPrefix +'['+ _f +']['+ mandatoryFields[m] +']'; \n // create input & add it to the form\n $newVirtualField = document.createElement('input');\n $newVirtualField.type = 'hidden';\n $newVirtualField.id = 'input.' + uuid.v4();\n $newVirtualField.name = _name;\n $newVirtualField.value = '';\n \n $el.form.appendChild($newVirtualField);\n hiddenFields[_f][ mandatoryFields[m] ] = $el.form[$el.form.length-1];// last added\n }\n \n }\n \n } // EO for files\n \n $uploadForm.uploadProperties = { \n id : $el.form.id || $el.getAttribute('id'),\n uploadTriggerId : $el.id,\n $form : $el.form,\n errorField : errorField,\n mandatoryFields : mandatoryFields,\n uploadFields : hiddenFields,\n hasPreviewContainer : hasPreviewContainer,\n isPopinContext : isPopinContext()\n };\n if (hasPreviewContainer) {\n $uploadForm.uploadProperties.previewContainer = previewContainer;\n }\n }\n \n if (eventOnSuccess)\n $uploadForm.setAttribute('data-gina-form-event-on-submit-success', eventOnSuccess);\n else\n $uploadForm.setAttribute('data-gina-form-event-on-submit-success', 'onGenericXhrResponse');\n \n if (eventOnError)\n $uploadForm.setAttribute('data-gina-form-event-on-submit-error', eventOnError);\n else\n $uploadForm.setAttribute('data-gina-form-event-on-submit-error', 'onGenericXhrResponse');\n \n \n // adding for to current document\n if (isPopinContext()) {\n //$activePopin.$target.appendChild($uploadForm)\n document.getElementById($activePopin.id).appendChild($uploadForm)\n } else {\n document.body.appendChild($uploadForm)\n } \n }\n \n // binding form\n try {\n var $uploadFormValidator = getFormById(uploadFormId);\n // create a FormData object which will be sent as the data payload in the \n var formData = new FormData();\n // add the files to formData object for the data payload\n var file = null; \n for (var l = 0, lLen = files.length; l < lLen; ++l) {\n file = files[l];\n formData.append(fileId, file, file.name);\n }\n \n $uploadFormValidator\n // .on('error', function(e, result) {\n // console.error('[error] ', '\\n(e)' + e, '\\n(result)' + result)\n // })\n // .on('success', function(e, result){\n \n // var $el = e.target;\n // var $preview = null, $ul = null, $li = null, $img = null;\n // var previewId = $el.getAttribute('data-gina-form-upload-preview') || null;\n // if (previewId)\n // $preview = document.getElementById(previewId);\n \n \n // var files = result.files;\n // if ($preview) {\n // $preview.innerHTML = '';\n // $ul = document.createElement(\"ul\");\n // for (var f = 0, fLen = files.length; f<fLen; ++f) {\n // $li = document.createElement(\"li\");\n // $img = document.createElement(\"img\");\n \n // $img.src = files[f].tmpSrc;\n // $img.width = files[f].width;\n // $img.height = files[f].height;\n \n // $li.appendChild($img);\n // $ul.appendChild($li);\n // }\n // $preview.appendChild($ul);\n // }\n \n // })\n /**.on('progress', function(evt, result) {\n \n percentComplete = result.progress;\n \n $progress.text(percentComplete + '%');\n $progress.width(percentComplete + '%');\n \n if (percentComplete === 100) {\n $progress.html('Done');\n }\n \n // if (evt.lengthComputable) {\n // // calculate the percentage of upload completed\n // var percentComplete = evt.loaded / evt.total;\n // percentComplete = parseInt(percentComplete * 100);\n \n // // update the Bootstrap progress bar with the new percentage\n // $progress.text(percentComplete + '%');\n // $progress.width(percentComplete + '%');\n \n // // once the upload reaches 100%, set the progress bar text to done\n // if (percentComplete === 100) {\n // $progress.html('Done');\n // }\n \n // }\n }) */ \n .send(formData, { withCredentials: true/*, isSynchrone: true*/ });\n \n } catch (formErr) {\n throw formErr;\n } \n }\n });\n \n \n }\n }// EO Binding input\n\n var updateSelect = function($el, $form) {\n $el.setAttribute('data-value', $el.value);\n // If Live check enabled, proceed to silent validation\n if ( /^(true)$/i.test($form.target.dataset.ginaFormLiveCheckEnabled && $form.rules.count() > 0) ) {\n var localField = {}, $localField = {}, $localForm = null;\n $localForm = $el.form;//event.target.form\n localField[event.target.name] = event.target.value;\n $localField[event.target.name] = event.target;\n \n instance.$forms[$localForm.getAttribute('id')].isValidating = true;\n validate(event.target, localField, $localField, $form.rules, function onLiveValidation(result){\n instance.$forms[$localForm.getAttribute('id')].isValidating = false;\n var isFormValid = result.isValid();\n //console.debug('onSilentPreGlobalLiveValidation: '+ isFormValid, result);\n if (isFormValid) {\n //resetting error display\n handleErrorsDisplay($localForm, {}, result.data, event.target.name);\n } else { \n handleErrorsDisplay($localForm, result.error, result.data, event.target.name);\n }\n //updateSubmitTriggerState( $localForm, isFormValid );\n // data-gina-form-required-before-submit\n //console.debug('====>', result.isValid(), result);\n \n // Global check required: on all fields\n var $gForm = $localForm, gFields = null, $gFields = null, gRules = null;\n var gValidatorInfos = getFormValidationInfos($gForm, rules);\n gFields = gValidatorInfos.fields;\n $gFields = gValidatorInfos.$fields;\n var formId = $gForm.getAttribute('id');\n gRules = instance.$forms[formId].rules;\n // Don't be tempted to revome fields that has already been validated\n instance.$forms[formId].isValidating = true;\n validate($gForm, gFields, $gFields, gRules, function onSilentGlobalLiveValidation(gResult){\n instance.$forms[formId].isValidating = false;\n console.debug('[updateSelect]: onSilentGlobalLiveValidation: '+ gResult.isValid(), gResult);\n var isFormValid = gResult.isValid();\n updateSubmitTriggerState( $gForm, isFormValid);\n once = false;\n })\n \n });\n }\n };\n // BO binding select\n var selectedIndex = null, selectedValue = null; \n for (var s = 0, sLen = $select.length; s < sLen; ++s) {\n checkForRuleAlias($form.rules, $select[s]);\n \n elId = $select[s].getAttribute('id');\n \n if (elId && /^gina\\-toolbar/.test(elId)) continue;\n\n if (!elId || elId == '') {\n elId = 'select.' + uuid.v4();\n $select[s].setAttribute('id', elId)\n }\n \n formElementGroupTmp = $select[s].getAttribute('data-gina-form-element-group');\n if (formElementGroupTmp) {\n let _name = $select[s].getAttribute('name') || elId;\n if (_name === elId) {\n $select[s].setAttribute('name', elId)\n }\n allFormGroupedElements[elId] = {\n id : elId,\n name : _name,\n group : formElementGroupTmp,\n target : $select[s]\n };\n }\n \n addListener(gina, $select[s], 'change', function(event) {\n var $el = event.target;\n \n if (/select/i.test($el.type) ) { \n updateSelect($el, $form);\n } \n });\n \n\n if ($select[s].options && !$form.fieldsSet[ elId ]) {\n selectedIndex = 0;\n selectedValue = $select[s].getAttribute('data-value') || null;\n if ( selectedValue ) {\n for (var o = 0, oLen = $select[s].options.length; o < oLen; ++o ) {\n if ( $select[s].options[o].value == selectedValue) {\n selectedIndex = o;\n $select[s].selectedIndex = selectedIndex;\n break\n }\n }\n }\n \n if ( typeof($select[s].options[$select[s].selectedIndex]) != 'undefined' && $select[s].options[ $select[s].selectedIndex ].index ) {\n selectedIndex = $select[s].options[ $select[s].selectedIndex ].index\n }\n\n $form.fieldsSet[ elId ] = {\n id : elId,\n name : $select[s].name || null,\n value : $select[s].options[ selectedIndex ].value || selectedValue || null,\n selectedIndex : selectedIndex || 0\n };\n\n // update select\n if ( typeof($select[s].selectedIndex) != 'undefined' ) {\n $select[s].options[ selectedIndex ].selected = true;\n $select[s].setAttribute('data-value', $select[s].options[ selectedIndex ].value);\n }\n\n }\n }// EO binding select\n \n // group dependencies handling\n var updateReletadItems = function(elId, group, excluded, isCalledHasDependency) {\n \n if ( typeof(isCalledHasDependency) == 'undefined' ) {\n isCalledHasDependency = false;\n }\n \n if ( typeof(allFormGroupedElements[elId]) == 'undefined' ) {\n throw new Error('Radio & Checkbox dependencies not met: you must use the ID attribue of the `master element` as the `data-gina-form-element-group`')\n }\n \n var elIdIsChecked = null\n , re = null\n , re2 = null\n , namedId = elId.replace(/\\-|\\_|\\@|\\#|\\.|\\[|\\]/g, '\\\\$&') \n //, name = $el.getAttribute('name').replace(/\\-|\\_|\\@|\\#|\\.|\\[|\\]/g, '\\\\$&')\n ;\n elIdIsChecked = allFormGroupedElements[elId].target.checked;\n //console.debug('current id ', elId, excluded);\n for (let id in allFormGroupedElements) {\n // ignore triggers\n if ( /radio|checkbox/i.test(allFormGroupedElements[id].target.type) )\n continue;\n \n let hasBeenUpdated = false; \n re = new RegExp(namedId);\n re2 = new RegExp(group); \n \n if ( \n re.test(allFormGroupedElements[id].group) && re2.test(allFormGroupedElements[id].group) \n ||\n re.test(allFormGroupedElements[id].group)\n ) {\n // init default state: disable all;\n allFormGroupedElements[id].target.disabled = true;\n // adding custom rule for this case\n if ( typeof($form.rules[ allFormGroupedElements[id].name ]) == 'undefined' ) {\n $form.rules[ allFormGroupedElements[id].name ] = {}\n }\n $form.rules[ allFormGroupedElements[id].name ].exclude = true;\n \n // triggered by click on the radio group \n if (isCalledHasDependency) {\n //console.debug('In Group #1 ', 'excluded:'+excluded, 'disabled:'+allFormGroupedElements[id].target.disabled, allFormGroupedElements[id].name, checkBoxGroup, ' VS ', allFormGroupedElements[id].group); \n allFormGroupedElements[id].target.disabled = (elIdIsChecked) ? false : true;\n $form.rules[ allFormGroupedElements[id].name ].exclude = (elIdIsChecked) ? false : true;\n //console.debug('In Group #1 fixed to -> ', 'excluded:'+excluded, 'disabled:'+allFormGroupedElements[id].target.disabled);\n continue;\n }\n // triggered by click on the checkbox\n //console.debug('In Group #2 ', 'excluded:'+excluded, 'disabled:'+allFormGroupedElements[id].target.disabled, allFormGroupedElements[id].name, checkBoxGroup, ' VS ', allFormGroupedElements[id].group);\n allFormGroupedElements[id].target.disabled = excluded;\n $form.rules[ allFormGroupedElements[id].name ].exclude = excluded;\n //console.debug('In Group #2 fixed to -> ', 'excluded:'+excluded, 'disabled:'+allFormGroupedElements[id].target.disabled);\n continue;\n }\n //console.debug('elId: '+elId, 'isCalledHasDependency:'+isCalledHasDependency, 'hasBeenUpdated:'+ hasBeenUpdated, 'excluded:'+excluded, 'disabled:'+allFormGroupedElements[id].target.disabled, allFormGroupedElements[id].name, 'elIdIsChecked:'+elIdIsChecked, 'inGroup:'+re.test(allFormGroupedElements[id].group) );\n \n }\n \n return\n };\n var handleCheckBoxGroupDependencies = function($form, $el, checkBoxGroup, isCalledHasDependency) {\n \n \n if ( typeof(isCalledHasDependency) == 'undefined' ) {\n isCalledHasDependency = false;\n }\n if (isCalledHasDependency && typeof(allFormGroupedElements[$el.id]) != 'undefined' ) {\n var excluded = /true/i.test($el.checked) ? false : true;\n return updateReletadItems($el.id, allFormGroupedElements[$el.id].group, excluded, isCalledHasDependency)\n }\n \n \n var item = $el.name;\n if (withRules && typeof($form.rules[item]) == 'undefined' ) { \n $form.rules[item] = {}\n } \n if ( /^true$/i.test($el.checked) ) { \n if (withRules) {\n $form.rules[item].exclude = false;\n if ( typeof(allFormGroupedElements[$el.id]) != 'undefined' ) {\n updateReletadItems($el.id, allFormGroupedElements[$el.id].group, false, isCalledHasDependency)\n }\n }\n } else {\n //elGroup[item].disabled = true;\n if (withRules) {\n $form.rules[item].exclude = true;\n if ( typeof(allFormGroupedElements[$el.id]) != 'undefined' ) {\n updateReletadItems($el.id, allFormGroupedElements[$el.id].group, true, isCalledHasDependency)\n }\n }\n }\n };\n var updateCheckBox = function($el, isInit) {\n if ( typeof(isInit) == 'undefined' ) {\n isInit = false;\n }\n \n var triggerHandleCheckBoxGroupDependencies = function($el, checkBoxGroup, isExcluded) {\n if (checkBoxGroup) {\n handleCheckBoxGroupDependencies($form, $el, checkBoxGroup);\n } else { \n for (let id in allFormGroupedElements) {\n if ( \n re.test(allFormGroupedElements[id].group)\n ||\n re.test(allFormGroupedElements[id].target.getAttribute('data-gina-form-element-group'))\n ) {\n allFormGroupedElements[id].target.disabled = isExcluded; \n }\n }\n } \n }\n \n // Preventing jQuery setting `on` value when input is not checked\n if (isInit && /^(on)$/i.test($el.value) && !$el.checked) {\n $el.value = false\n }\n var localValue = $el.getAttribute('data-value') || $el.getAttribute('value') || $el.value;\n localValue = (/^(true|on)$/.test(localValue)) ? true : localValue;\n \n if (localValue === '') {\n localValue = false\n }\n var isLocalBoleanValue = ( /^(true|on|false)$/i.test(localValue) ) ? true : false;\n if (isInit && isLocalBoleanValue) { // on checkbox init\n // update checkbox initial state\n // Value defines checked state by default\n if ( /^true$/i.test(localValue) && !$el.checked) {\n $el.checked = true;\n } else if ( /^false$/i.test(localValue) && $el.checked) {\n $el.checked = false;\n }\n }\n var checked = $el.checked;\n \n var checkBoxGroup = $el.getAttribute('data-gina-form-element-group') || null;\n var re = new RegExp($el.id.replace(/\\-|\\_|\\@|\\#|\\.|\\[|\\]/g, '\\\\$&'));\n // set to checked if not checked: false -> true\n if ( !checked || checked == 'null' || checked == 'false' || checked == '' ) {\n\n // prevents ticking behavior\n if (!isInit) {\n setTimeout(function () {\n $el.checked = false;\n // means that the checkbox is member of another group\n triggerHandleCheckBoxGroupDependencies($el, checkBoxGroup, true);\n updateGroupChildrenState($el);\n }, 0);\n } else {\n updateGroupChildrenState($el);\n }\n \n \n $el.removeAttribute('checked');\n if (isLocalBoleanValue) {\n $el.value = false;\n $el.setAttribute('value', 'false');\n if ( typeof($el.getAttribute('data-value') != 'undefined' ) )\n $el.setAttribute('data-value', 'false');\n }\n \n \n } else { \n \n // prevents ticking behavior\n if (!isInit) {\n setTimeout(function () {\n $el.checked = true;\n // means that the checkbox is member of another group\n triggerHandleCheckBoxGroupDependencies($el, checkBoxGroup, false); \n updateGroupChildrenState($el);\n }, 0);\n $el.setAttribute('checked', 'checked');\n } else {\n updateGroupChildrenState($el);\n }\n \n if (isLocalBoleanValue) {\n $el.value = true;\n $el.setAttribute('value', true);\n if ( typeof($el.getAttribute('data-value') != 'undefined' ) )\n $el.setAttribute('data-value', true);\n }\n \n }\n };\n \n var updateGroupChildrenState = function($groupMaster) {\n var re = new RegExp($groupMaster.id.replace(/\\-|\\_|\\@|\\#|\\.|\\[|\\]/g, '\\\\$&'));\n // Handle extended groups\n for (let id in allFormGroupedElements) {\n if ( \n /checkbox/i.test(allFormGroupedElements[id].target.type) && re.test(allFormGroupedElements[id].group)\n ||\n /checkbox/i.test(allFormGroupedElements[id].target.type) && re.test(allFormGroupedElements[id].target.getAttribute('data-gina-form-element-group'))\n ) {\n handleCheckBoxGroupDependencies($form, allFormGroupedElements[id].target, allFormGroupedElements[id].group, true); \n }\n }\n }\n \n // When binding children element to the radio, you must used the radio.id as the element group\n // Because the name attribute of the radio can also be used to group multiple radio field\n // On master: <input type=\"radio\" id=\"invoice-type-balance\" name=\"action[addFromExisting]\" value=\"balanceFlow\">\n // On children: <input type=\"checkbox\" data-gina-form-element-group=\"invoice-type-balance\" value=\"someValue\">\n var handleGroupDependencies = function($el, isOnResetMode) {\n isOnResetMode = ( typeof(isOnResetMode) != 'undefined' && isOnResetMode) ? true: false;\n \n //console.debug('reset: '+isOnResetMode, $el.id, $el.checked);\n var extendedGroupName = $el.id.replace(/\\-|\\_|\\@|\\#|\\.|\\[|\\]/g, '\\\\$&')\n , re = null\n ;\n // parse grouped elements: allFormGroupedElements\n // init\n re = new RegExp(extendedGroupName);\n for (let id in allFormGroupedElements) { \n if (!/checkbox|radio/i.test(allFormGroupedElements[id].target.type)) {\n allFormGroupedElements[id].target.disabled = true;\n // adding custom rule for this case\n if ( typeof($form.rules[ allFormGroupedElements[id].name ]) == 'undefined' ) {\n $form.rules[ allFormGroupedElements[id].name ] = {}\n }\n $form.rules[ allFormGroupedElements[id].name ].exclude = true;\n }\n \n if ( \n re.test(allFormGroupedElements[id].group) \n ||\n re.test(allFormGroupedElements[id].target.getAttribute('data-gina-form-element-group').replace(/\\-|\\_|\\@|\\#|\\.|\\[|\\]/g, '\\\\$&')) \n ) { \n // init default\n allFormGroupedElements[id].target.disabled = true;\n // adding custom rule for this case\n if ( typeof($form.rules[ allFormGroupedElements[id].name ]) == 'undefined' ) {\n $form.rules[ allFormGroupedElements[id].name ] = {}\n }\n \n if (/^(true|on)$/i.test($el.checked)) {\n allFormGroupedElements[id].target.disabled = false;\n $form.rules[ allFormGroupedElements[id].name ].exclude = false;\n } else {\n allFormGroupedElements[id].target.disabled = true; \n $form.rules[ allFormGroupedElements[id].name ].exclude = true;\n }\n }\n }\n // Handle extended groups\n updateGroupChildrenState($el);\n }\n \n // BO Binding radio\n var radioGroup = null;\n var updateRadio = function($el, isInit, isTriggedByUser) {\n isInit = ( typeof(isInit) == 'undefined' || !isInit ) ? false : true;\n isTriggedByUser = ( typeof(isTriggedByUser) == 'undefined' || !isTriggedByUser ) ? false : true;\n \n var checked = $el.checked, evt = null;\n var isBoolean = /^(true|false)$/i.test($el.value);\n radioGroup = document.getElementsByName($el.name);\n\n // loop if radio group\n for (let r = 0, rLen = radioGroup.length; r < rLen; ++r) {\n if (radioGroup[r].id !== $el.id && checked) {\n radioGroup[r].checked = false;\n radioGroup[r].removeAttribute('checked');\n handleGroupDependencies(radioGroup[r], true)\n }\n }\n \n \n if (isInit) {\n handleGroupDependencies($el);\n return;\n }\n\n if ( !checked || checked == 'null' || checked == 'false' || checked == '' ) {\n\n // prevents ticking behavior\n setTimeout(function () {\n if (isTriggedByUser) {\n handleGroupDependencies($el);\n return;\n } \n $el.checked = true;\n $el.setAttribute('checked', 'checked');\n }, 0)\n \n } else {\n\n // prevents ticking behavior\n setTimeout(function () {\n if (isTriggedByUser) {\n handleGroupDependencies($el);\n return;\n }\n $el.checked = false;\n $el.removeAttribute('checked');\n }, 0)\n }\n\n if (isBoolean) { // force boolean value\n $el.value = (/^true$/.test($el.value)) ? true : false\n }\n // fix added on 2020/09/25 : \n return;\n }// EO Binding radio\n \n for (var i = 0, iLen = $inputs.length; i < iLen; ++i) {\n type = $inputs[i].getAttribute('type');\n\n if ( typeof($inputs[i].id) == 'undefined' || $inputs[i].id == '' ) {\n $inputs[i].id = type +'-'+ uuid.v4();\n $inputs[i].setAttribute('id', $inputs[i].id)\n }\n\n\n // recover default state only on value === true || false || on\n if ( \n typeof(type) != 'undefined' \n && /^checkbox$/i.test(type) \n ) {\n \n // if is master of a group, init children default state \n if ( \n $inputs[i].disabled \n && allFormGroupNames.indexOf($inputs[i].id) > -1 \n ||\n !$inputs[i].checked \n && allFormGroupNames.indexOf($inputs[i].id) > -1\n ) {\n // updateGroupChildrenState($inputs[i]);\n let re = new RegExp( $inputs[i].id.replace(/\\-|\\_|\\@|\\#|\\.|\\[|\\]/g, '\\\\$&') ); \n for (let childElement in allFormGroupedElements ) {\n if ( re.test(allFormGroupedElements[childElement].group) ) {\n allFormGroupedElements[childElement].target.disabled = true;\n }\n } \n } \n\n evt = 'change.'+ $inputs[i].id;\n proceed = function ($el, evt) {\n\n // recover default state only on value === true || false \n addListener(gina, $el, evt, function(event) { \n updateCheckBox(event.target);\n \n triggerEvent(gina, event.target, 'changed.'+ event.target.id); \n });\n\n // default state recovery\n updateCheckBox($el, true); \n }\n\n if ( typeof(gina.events[evt]) != 'undefined' && gina.events[evt] == $inputs[i].id ) {\n removeListener(gina, $inputs[i], evt);\n proceed($inputs[i], evt)\n\n } else {\n proceed($inputs[i], evt)\n }\n\n } else if (\n typeof(type) != 'undefined' \n && /^radio$/i.test(type) \n ) {\n\n evt = $inputs[i].id;\n //evt = 'change.'+ $inputs[i].id;\n\n proceed = function ($el, evt) {\n // recover default state\n addListener(gina, $el, evt, function(event) {\n //cancelEvent(event);\n updateRadio(event.target);\n \n triggerEvent(gina, event.target, 'changed.'+ event.target.id); \n });\n \n // default state recovery\n updateRadio($el, true);\n }\n\n if ( typeof(gina.events[evt]) != 'undefined' && gina.events[evt] == $inputs[i].id ) {\n removeListener(gina, $inputs[i], evt);\n proceed($inputs[i], evt);\n } else {\n proceed($inputs[i], evt)\n }\n }\n }\n \n\n evt = 'click';\n\n proceed = function () {\n var subEvent = null;\n // handle form reset\n subEvent = 'reset.'+$target.id;\n if ( typeof(gina.events[subEvent]) == 'undefined' ) {\n addListener(gina, $target, subEvent, function(e) {\n e.preventDefault();\n \n var _id = e.currentTarget.id || e.target.id\n var $form = instance.$forms[_id];\n $form.target.dataset.ginaFormIsResetting = true;\n resetFields($form);\n // forcing it\n var validationInfo = getFormValidationInfos($form.target, $form.rules, true);\n var fields = validationInfo.fields;\n var $fields = validationInfo.$fields; \n \n validate($form.target, fields, $fields, $form.rules, function onSilentResetValidation(result){\n var isFormValid = result.isValid();\n console.debug('silent reset validation result[isValid:'+isFormValid+']: ', result);\n //resetting error display\n handleErrorsDisplay($form.target, {});\n \n updateSubmitTriggerState( $form.target , isFormValid );\n $form.target.dataset.ginaFormIsResetting = false;\n });\n })\n }\n // reset proxy \n addListener(gina, $target, 'reset', function(event) {\n var $el = event.target;\n // prevent event to be triggered twice\n if ( \n typeof(event.defaultPrevented) != 'undefined' \n && event.defaultPrevented \n ) {\n return false;\n }\n // Fixed on 2021/06/08 - because of radio reset\n event.preventDefault();\n \n var _evt = $el.id; \n if (!_evt) return false;\n\n if ( !/^reset\\./.test(_evt) ) {\n _evt = 'reset.'+$el.id\n }\n if (gina.events[_evt]) {\n triggerEvent(gina, $el, _evt, event.detail);\n }\n });\n // keydown proxy \n addListener(gina, $target, 'keydown', function(event) {\n var $el = event.target;\n // prevent event to be triggered twice\n if ( typeof(event.defaultPrevented) != 'undefined' && event.defaultPrevented )\n return false;\n \n keyboardMapping[event.keyCode] = event.type == 'keydown';\n \n var _evt = $el.id; \n if (!_evt) return false;\n\n if ( !/^keydown\\./.test(_evt) ) {\n _evt = 'keydown.'+$el.id\n }\n if (gina.events[_evt]) {\n cancelEvent(event);\n triggerEvent(gina, $el, _evt, event.detail, event);\n }\n });\n // keyup proxy - updating keyboardMapping \n addListener(gina, $target, 'keyup', function(event) {\n var $el = event.target;\n // prevent event to be triggered twice\n if ( typeof(event.defaultPrevented) != 'undefined' && event.defaultPrevented )\n return false;\n \n if (keyboardMapping[event.keyCode]) {\n delete keyboardMapping[event.keyCode]\n }\n \n var _evt = $el.id; \n if (!_evt) return false;\n if ( !/^keyup\\./.test(_evt) ) {\n _evt = 'keyup.'+$el.id\n }\n if (gina.events[_evt]) {\n cancelEvent(event);\n triggerEvent(gina, $el, _evt, event.detail, event);\n }\n });\n \n // focusin proxy \n addListener(gina, $target, 'focusin', function(event) {\n var $el = event.target;\n // prevent event to be triggered twice\n if ( typeof(event.defaultPrevented) != 'undefined' && event.defaultPrevented )\n return false;\n \n var _evt = $el.id; \n if (!_evt) return false;\n\n if ( !/^focusin\\./.test(_evt) ) {\n _evt = 'focusin.'+$el.id\n }\n if (gina.events[_evt]) {\n cancelEvent(event);\n \n triggerEvent(gina, $el, _evt, event.detail);\n }\n });\n // focusout proxy \n addListener(gina, $target, 'focusout', function(event) {\n // Never preventDefault from a proxy listner\n var $el = event.target;\n // prevent event to be triggered twice\n if ( typeof(event.defaultPrevented) != 'undefined' && event.defaultPrevented )\n return false;\n \n var _evt = $el.id; \n if (!_evt) return false;\n\n if ( !/^focusout\\./.test(_evt) ) {\n _evt = 'focusout.'+$el.id\n }\n if (gina.events[_evt]) {\n cancelEvent(event);\n \n triggerEvent(gina, $el, _evt, event.detail);\n }\n }); \n \n // change proxy\n addListener(gina, $target, 'change', function(event) {\n // Never preventDefault from a proxy listner\n var $el = event.target;\n // prevent event to be triggered twice\n if ( typeof(event.defaultPrevented) != 'undefined' && event.defaultPrevented )\n return false;\n \n var _evt = $el.id; \n if (!_evt) return false;\n\n if ( !/^change\\./.test(_evt) ) {\n _evt = 'change.'+$el.id\n }\n if (gina.events[_evt]) {\n cancelEvent(event);\n triggerEvent(gina, $el, _evt, event.detail);\n }\n }); \n // click proxy \n addListener(gina, $target, 'click', function(event) { \n // Never preventDefault from a proxy listner \n var $el = event.target;\n // prevent event to be triggered twice\n // if ( typeof(event.defaultPrevented) != 'undefined' && event.defaultPrevented )\n // return false;\n \n var isCustomSubmit = false, isCaseIgnored = false;\n \n if (\n /(label)/i.test(event.target.tagName) \n && typeof(event.target.control) != 'undefined' \n && event.target.control != null \n && /(checkbox|radio)/i.test(event.target.control.type) \n || \n /(label)/i.test(event.target.parentNode.tagName) \n && typeof(event.target.parentNode.control) != 'undefined' \n && event.target.parentNode.control != null \n && /(checkbox|radio)/i.test(event.target.parentNode.control.type) \n ) { \n var isCaseIgnored = ( \n event.target.getAttribute('for') \n || \n event.target.parentNode.getAttribute('for')\n ) ? true : false\n ; \n // if `event.target.control` not working on all browser,\n // try to detect `for` attribute OR check if on of the label's event.target.children is an input & type == (checkbox|radio)\n $el = event.target.control || event.target.parentNode.control;\n \n }\n if ( \n !$el.disabled \n && /(checkbox|radio)/i.test($el.type) \n && !isCaseIgnored\n ) {\n // apply checked choice : if true -> set to false, and if false -> set to true \n if ( /checkbox/i.test($el.type) ) {\n return updateCheckBox($el);\n } else if ( /radio/i.test($el.type) ) {\n return updateRadio($el, false, true);\n }\n } \n \n \n // include only these elements for the binding\n if ( \n /(button|input)/i.test($el.tagName) && /(submit|checkbox|radio)/i.test($el.type)\n || /a/i.test($el.tagName) && $el.attributes.getNamedItem('data-gina-form-submit')\n // You could also have a click on a child element like <a href=\"#\"><span>click me</span></a>\n || /a/i.test($el.parentNode.tagName) && $el.parentNode.attributes.getNamedItem('data-gina-form-submit')\n ) { \n var namedItem = $el.attributes.getNamedItem('data-gina-form-submit');\n var parentNamedItem = $el.parentNode.attributes.getNamedItem('data-gina-form-submit');\n if (\n namedItem\n ||\n parentNamedItem \n ) { \n isCustomSubmit = true;\n // Get others attribute and override current form attribute \n var newFormMethod = null;\n if (namedItem) {\n newFormMethod = $el.getAttribute('data-gina-form-submit-method');\n } else {\n newFormMethod = $el.parentNode.getAttribute('data-gina-form-submit-method');\n }\n if (newFormMethod) {\n // Backup originalMethod\n \n // Rewrite current method\n if (namedItem && $el.form) {\n $el.form.setAttribute('method', newFormMethod);\n } else if ($el.parentNode.form) {\n $el.parentNode.form.setAttribute('method', newFormMethod);\n }\n }\n }\n \n if ( typeof($el.id) == 'undefined' || !$el.getAttribute('id') ) {\n $el.setAttribute('id', 'click.' + uuid.v4() );\n $el.id = $el.getAttribute('id')\n } else {\n $el.id = $el.getAttribute('id')\n }\n \n \n if (/^click\\./.test($el.id) || withRules) {\n \n var _evt = $el.id;\n \n if (!_evt) return false;\n \n if ( !/^click\\./.test(_evt) ) {\n _evt = $el.id\n }\n \n // normal case\n if (\n !$el.disabled \n && /(checkbox|radio)/i.test($el.type) \n ) {\n //event.stopPropagation(); \n // apply checked choice : if true -> set to false, and if false -> set to true \n if ( /checkbox/i.test($el.type) ) {\n return updateCheckBox($el);\n } else if ( /radio/i.test($el.type) ) {\n return updateRadio($el, false, true);\n }\n }\n \n // prevent event to be triggered twice\n if ( typeof(event.defaultPrevented) != 'undefined' && event.defaultPrevented )\n return false;\n \n // in case we have multiple submit type buttons\n if ( $el.type == 'submit' && !/^submit\\./i.test(_evt) ) {\n _evt = 'submit.'+_evt\n }\n // in case we have multiple reset type buttons\n if ( $el.type == 'reset' && !/^reset\\./i.test(_evt) ) {\n _evt = 'reset.'+_evt\n }\n \n if (gina.events[_evt]) {\n cancelEvent(event);\n \n triggerEvent(gina, $el, _evt, event.detail);\n } else if ( \n isCustomSubmit\n && typeof(this.id) != 'undefined'\n && this.id != ''\n && typeof(gina.validator.$forms[this.id]) != 'undefined'\n ) {\n gina.validator.getFormById(this.id).submit();\n cancelEvent(event); // stop #navigation\n }\n \n }\n } \n\n })\n }\n \n proceed();\n\n \n \n\n\n evt = 'validate.' + _id;\n proceed = function () {\n // attach form submit event\n addListener(gina, $target, evt, function(event) {\n cancelEvent(event);\n \n //var result = event['detail'] || $form.eventData.error || $form.eventData.validation;\n var result = $form.eventData.error || $form.eventData.validation || event['detail'];\n // TODO - Since $form.eventData.error is cached, add a TTL to clear it and allow re $validator.send()\n handleErrorsDisplay(event['target'], result['fields']||result['error'], result['data']);\n\n var _id = event.target.getAttribute('id');\n\n if ( typeof(result['isValid']) != 'undefined' && result['isValid']() ) { // send if valid\n // Experimental - inheritedData\n // Inhertitance from previously posted form: merging datas with current form context\n // TODO - Get the inhereted data from LMDB Database using the form CSRF\n var inheritedData = instance.$forms[_id].target.getAttribute('data-gina-form-inherits-data') || null;\n if (inheritedData) { \n result['data'] = merge(result['data'], JSON.parse(decodeURIComponent(inheritedData)) )\n }\n // now sending to server\n if (instance.$forms[_id]) {\n instance.$forms[_id].send(result['data']);\n } else if ($form) { // just in case the form is being destroyed\n $form.send(result['data']);\n }\n }\n })\n }\n // cannot be binded twice\n if ( typeof(gina.events[evt]) != 'undefined' && gina.events[evt] == 'validate.' + _id ) {\n removeListener(gina, $form, evt, proceed)\n }\n \n proceed();\n\n var proceedToSubmit = function (evt, $submit) {\n // attach submit events\n if ( !/^submit\\./i.test(evt) ) {\n evt = 'submit.'+ evt;\n } \n //console.debug('attaching submit event: `'+ evt +'` on `'+ $submit.id + '` element for form `'+ $submit.form.id +'`');\n addListener(gina, $submit, evt, function(event) {\n // start validation\n cancelEvent(event);\n\n // getting fields & values\n var $fields = {}\n , fields = { '_length': 0 }\n , id = $target.getAttribute('id')\n , rules = ( typeof(instance.$forms[id]) != 'undefined' ) ? instance.$forms[id].rules : null\n , name = null\n , value = 0\n , type = null\n , index = { checkbox: 0, radio: 0 }\n , isDisabled = null \n ;\n \n // stop there if form has already been sent\n if (instance.$forms[id].sent) {\n return;\n }\n \n var validatorInfos = getFormValidationInfos($target, rules);\n fields = validatorInfos.fields;\n $fields = validatorInfos.$fields;\n rules = instance.$forms[id].rules;\n \n\n if ( fields['_length'] == 0 ) { // nothing to validate\n delete fields['_length'];\n var result = {\n 'error' : [],\n 'isValid' : function() { return true },\n 'data' : formatData(fields)\n };\n\n triggerEvent(gina, $target, 'validate.' + _id, result)\n\n } else {\n // update rule in case the current event is triggered outside the main sequence\n // e.g.: form `id` attribute rewritten on the fly\n _id = $target.getAttribute('id');\n var customRule = $target.getAttribute('data-gina-form-rule');\n\n if ( customRule ) { // 'data-gina-form-rule'\n rule = getRuleObjByName(customRule.replace(/\\-|\\//g, '.'))\n } else {\n rule = getRuleObjByName(_id.replace(/\\-/g, '.'))\n }\n instance.$forms[id].isSubmitting = true;\n instance.$forms[id].isSending = false;\n validate($target, fields, $fields, rule, function onClickValidation(result){\n triggerEvent(gina, $target, 'validate.' + _id, result)\n })\n }\n });\n }\n\n\n // BO binding submit button\n var $submit = null\n , $buttons = []\n , $buttonsTMP = []\n , linkId = null \n , buttonId = null\n ;\n $buttonsTMP = $target.getElementsByTagName('button');\n if ( $buttonsTMP.length > 0 ) {\n for(let b = 0, len = $buttonsTMP.length; b < len; ++b) {\n if ($buttonsTMP[b].type == 'submit') {\n $buttons.push($buttonsTMP[b])\n } \n }\n }\n\n // binding links\n $buttonsTMP = $target.getElementsByTagName('a'); \n if ( $buttonsTMP.length > 0 ) {\n for(let b = 0, len = $buttonsTMP.length; b < len; ++b) {\n if ( $buttonsTMP[b].attributes.getNamedItem('data-gina-form-submit') ) {\n $buttons.push($buttonsTMP[b])\n } else if ( \n !$buttonsTMP[b].getAttribute('id') \n && !/gina\\-popin/.test($buttonsTMP[b].className) \n && !gina.popinIsBinded\n && !/gina\\-link/.test($buttonsTMP[b].className) \n ) { // will not be binded but will receive an id if not existing\n linkId = 'link.'+ uuid.v4();\n $buttonsTMP[b].id = linkId;\n }\n }\n }\n\n // \n var onclickAttribute = null, isSubmitType = false;\n for (let b=0, len=$buttons.length; b<len; ++b) {\n\n $submit = $buttons[b];\n // retrieve submitTrigger\n if (\n /button/i.test($submit.tagName) \n && typeof($submit.type) != 'undefined'\n && /submit/i.test($submit.type)\n ||\n /a/i.test($submit.tagName) \n && typeof($submit.dataset.ginaFormSubmit) != 'undefined'\n && /^true$/i.test($submit.dataset.ginaFormSubmit)\n ||\n /a/i.test($submit.parentNode.tagName)\n && typeof($submit.parentNode.dataset.ginaFormSubmit) != 'undefined'\n && /^true$/i.test($submit.parentNode.dataset.ginaFormSubmit)\n ) {\n if ( /a/i.test($submit.parentNode.tagName) ) {\n $submit = $submit.parentNode;\n }\n \n if ( typeof($submit.id) == 'undefined' || typeof($submit.id) != 'undefined' && $submit.id == \"\" ) {\n $submit.id = 'click.'+uuid.v4();\n $submit.setAttribute('id', $submit.id);\n }\n \n if ( /a/i.test($submit.tagName) && typeof($submit.form) == 'undefined' ) {\n $submit.form = { id: $form.id };\n }\n \n /**if ( typeof(instance.$forms[$form.id].submitTrigger) != 'undefined' && $submit.form.id !== instance.$forms[$form.id].submitTrigger ) {\n console.warn('Form `submitTrigger` is already defined for your form #'+ $submit.form.id +': cannot attach `'+$submit.id+'`');\n } else */\n if (\n typeof($submit.dataset.ginaFormSubmitTriggerFor) == 'undefined'\n && typeof(instance.$forms[$form.id]) != 'undefined'\n && typeof(instance.$forms[$form.id].submitTrigger) == 'undefined' \n && typeof($submit.form.id) != 'undefined'\n && $form.id == $submit.form.id\n ) {\n console.debug('attching submitTrigger: '+ $submit.id, ' \\ form id: '+ $form.id);\n instance.$forms[$form.id].submitTrigger = $form.submitTrigger = $submit.id || $submit.getAttribute('id');\n // mark submitTrigger\n $submit.dataset.ginaFormSubmitTriggerFor = $form.id;\n } // else, skipping\n }\n\n if ($submit.tagName == 'A') { // without this test, XHR callback is ignored\n //console.debug('a#$buttons ', $buttonsTMP[b]);\n onclickAttribute = $submit.getAttribute('onclick');\n isSubmitType = $submit.getAttribute('data-gina-form-submit');\n\n if ( !onclickAttribute && !isSubmitType) {\n $submit.setAttribute('onclick', 'return false;')\n } else if ( !/return false/i.test(onclickAttribute) && !isSubmitType) {\n if ( /\\;$/.test(onclickAttribute) ) {\n onclickAttribute += 'return false;'\n } else {\n onclickAttribute += '; return false;'\n }\n }\n }\n\n if (!$submit['id']) {\n evt = 'click.'+ uuid.v4();\n $submit['id'] = evt;\n $submit.setAttribute( 'id', evt);\n } else {\n evt = $submit['id'];\n }\n \n if ( typeof(gina.events[evt]) == 'undefined' || gina.events[evt] != $submit.id ) {\n proceedToSubmit(evt, $submit)\n }\n\n }// BO binding submit button\n\n evt = 'submit';\n \n // submit proxy\n addListener(gina, $target, evt, function(e) {\n\n var $target = e.target\n , id = $target.getAttribute('id')\n , $formInstance = instance.$forms[id]\n , isBinded = $form.binded\n ;\n \n // check submit trigger status\n var submitTrigger = new DOMParser()\n .parseFromString($target.innerHTML, 'text/html')\n .getElementById($formInstance.submitTrigger);\n // prevent submit if disabled\n if ( submitTrigger && submitTrigger.disabled) {\n cancelEvent(e);\n }\n\n // prevent event to be triggered twice\n if ( typeof(e.defaultPrevented) != 'undefined' && e.defaultPrevented )\n return false;\n\n if (withRules || isBinded) {\n cancelEvent(e);\n }\n\n\n // just collect data over forms\n // getting fields & values\n var $fields = {}\n , fields = { '_length': 0 }\n , id = $target.getAttribute('id')\n , rules = ( typeof(gina.validator.$forms[id]) != 'undefined' ) ? gina.validator.$forms[id].rules : null\n , name = null\n , value = 0\n , type = null\n , index = { checkbox: 0, radio: 0 }\n , isDisabled = null \n ;\n\n\n for (var i = 0, len = $target.length; i<len; ++i) {\n \n name = $target[i].getAttribute('name');\n // NB.: If you still want to save the info and you main field is disabled;\n // consider using an input type=hidden of validator rule `\"exclude\" : false`\n isDisabled = $target[i].disabled || $target[i].getAttribute('disabled'); \n isDisabled = ( /disabled|true/i.test(isDisabled) ) ? true : false;\n\n if (!name) continue;\n if (isDisabled) continue;\n\n // checkbox or radio\n if ( typeof($target[i].type) != 'undefined' && $target[i].type == 'radio' || typeof($target[i].type) != 'undefined' && $target[i].type == 'checkbox' ) {\n\n if ( $target[i].checked ) {\n // if is boolean\n if ( /^(true|false)$/.test($target[i].value) ) {\n fields[name] = $target[i].value = (/^true$/.test($target[i].value)) ? true : false\n } else {\n fields[name] = $target[i].value\n }\n\n } else if ( // force validator to pass `false` if boolean is required explicitly\n rules\n && typeof(rules[name]) != 'undefined'\n && typeof (rules[name].isBoolean) != 'undefined' && $target[i].type == 'checkbox'\n //&& typeof(rules[name].isRequired) != 'undefined'\n && !/^(true|false)$/.test($target[i].value)\n ) {\n fields[name] = false;\n }\n\n } else {\n fields[name] = $target[i].value;\n }\n\n\n\n $fields[name] = $target[i];\n // reset filed error data attributes\n $fields[name].setAttribute('data-gina-form-errors', '');\n\n //++fields['_length']\n }\n fields['_length'] = fields.count();\n\n\n if ( fields['_length'] == 0 ) { // nothing to validate\n\n delete fields['_length'];\n var result = {\n 'error' : [],\n 'isValid' : function() { return true },\n 'data' : formatData(fields)\n };\n\n if ( typeof(gina.events['submit.' + id]) != 'undefined' ) { // if `on('submit', cb)` is binded\n triggerEvent(gina, $target, 'submit.' + id, result);\n } else {\n triggerEvent(gina, $target, 'validate.' + id, result);\n }\n\n } else {\n // update rule in case the current event is triggered outside the main sequence\n // e.g.: form `id` attribute rewritten on the fly\n var customRule = $target.getAttribute('data-gina-form-rule');\n\n if ( customRule ) { // 'data-gina-form-rule'\n rule = getRuleObjByName(customRule.replace(/\\-|\\//g, '.'))\n } else {\n rule = getRuleObjByName(id.replace(/\\-/g, '.'))\n }\n instance.$forms[id].isValidating = true;\n validate($target, fields, $fields, rule, function onSubmitValidation(result){\n instance.$forms[id].isValidating = false;\n // var isFormValid = result.isValid();\n // if (isFormValid) {\n // //resetting error display\n // handleErrorsDisplay($target, {}, result.data);\n // } else { \n // handleErrorsDisplay($target, result.error, result.data);\n if ( typeof(gina.events['submit.' + id]) != 'undefined' ) { // if `on('submit', cb)` is binded\n triggerEvent(gina, $target, 'submit.' + id, result);\n } else {\n triggerEvent(gina, $target, 'validate.' + id, result);\n }\n return;\n // }\n })\n }\n });\n \n \n \n instance.$forms[_id]['binded'] = true; \n // If Live check enabled, proceed to silent validation\n if ( /^(true)$/i.test($form.target.dataset.ginaFormLiveCheckEnabled && $form.rules.count() > 0) ) {\n console.debug('silent validation mode on');\n var validationInfo = getFormValidationInfos($form.target, $form.rules);\n var fields = validationInfo.fields;\n var $fields = validationInfo.$fields;\n validate($form.target, fields, $fields, $form.rules, function onSilentValidation(result){ \n console.debug('silent validation result[isValid:'+result.isValid()+']: ', result);\n if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) {\n // update toolbar\n if (!gina.forms.errors)\n gina.forms.errors = {};\n \n var objCallback = {\n id : _id,\n errors : result.error //,\n // we might also need to update rules in case of form ajax changes\n // rules : $form.rules,\n // data : result.data\n };\n \n window.ginaToolbar.update('forms', objCallback);\n }\n updateSubmitTriggerState( $form, result.isValid() );\n });\n } else if (!/^(true)$/i.test($form.target.dataset.ginaFormLiveCheckEnabled) ) {\n updateSubmitTriggerState( $form , true );\n }\n \n } // EO bindForm()\n \n var updateSubmitTriggerState = function($formInstanceOrTarget, isFormValid) {\n //console.debug('submitTrigger[isFormValid='+ isFormValid +']: ', $formInstance.submitTrigger)\n $formInstance = null;\n if ( $formInstanceOrTarget instanceof HTMLFormElement ) { // is target DOMobject\n var id = $formInstanceOrTarget.getAttribute('id');\n $formInstance = instance.$forms[id];\n } else {\n $formInstance = $formInstanceOrTarget;\n }\n //if (!$formInstance) return;\n \n if ( typeof($formInstance.submitTrigger) == 'undefined') {\n console.warn('This might be normal, so do not worry if this form is handled by your javascript: `'+ $formInstance.id +'`\\nGina could not complete `updateSubmitTriggerState()`: `submitTrigger` might not be attached to form instance `'+ $formInstance.id +'`\\nTo disable this warning, You just need to disable `Form Live Checking on your form by adding to your <form>: `data-gina-form-live-check-enabled=false``')\n } else if ( document.getElementById($formInstance.submitTrigger) ) {\n if ( /true/i.test(isFormValid) ) { // show submitTrigge\n document.getElementById($formInstance.submitTrigger).disabled = false;\n } else { // hide submitTrigger\n document.getElementById($formInstance.submitTrigger).disabled = true;\n }\n }\n }\n \n /**\n * getFormValidationInfos\n * \n * @param {object} $form - form target (DOMObject), not the instance\n * @param {object} [rules]\n * \n * @return {object} { .fields, .$fields, .rules }\n */\n var getFormValidationInfos = function($form, rules, isOnResetMode) {\n // patching form reset\n if (typeof(isOnResetMode) == 'undefined') {\n isOnResetMode = false;\n }\n // getting fields & values\n var $fields = {}\n , fields = {}//{ '_length': 0 }\n , id = $form.id || $form.getAttribute('id')\n , name = null\n , value = 0\n , type = null\n , index = { checkbox: 0, radio: 0 }\n , isDisabled = null\n ;\n if ( typeof(rules) == 'undefined' ) {\n rules = ( typeof(instance.$forms[id].rules) != 'undefined' && instance.$forms[id].rules.count() > 0 ) ? instance.$forms[id].rules : null;\n if (!rules && typeof(gina.validator.$forms[id]) != 'undefined') {\n rules = gina.validator.$forms[id].rules\n }\n }\n\n // BO Parsing form elements\n for (var i = 0, len = $form.length; i<len; ++i) { \n if ( isOnResetMode ) {\n // reset form values\n switch ($form[i].tagName.toLowerCase()) {\n case 'input':\n if ( /^(hidden|text)$/i.test($form[i].type) ) {\n $form[i].value = $form[i].defaultValue;\n }\n break;\n \n default:\n break;\n }\n }\n \n // retrieve submitTrigger\n if (\n /button/i.test($form[i].tagName) \n && typeof($form[i].type) != 'undefined'\n && /submit/i.test($form[i].type)\n ||\n /a/i.test($form[i].tagName) \n && typeof($form[i].dataset.ginaFormSubmit) != 'undefined'\n && /^true$/i.test($form[i].dataset.ginaFormSubmit)\n ) {\n if ( /a/i.test($form[i].tagName) && typeof($form[i].form) == 'undefined' ) {\n $form[i].form = { id: id };\n }\n /**if ( typeof(instance.$forms[id].submitTrigger) != 'undefined' && $form[i].form.id !== instance.$forms[id].submitTrigger ) {\n console.warn('Form `submitTrigger` is already defined for your form `#'+ $form[i].form.id +'`: cannot attach `'+$form[i].id+'`');\n } else */\n if ( \n typeof($form[i].dataset.ginaFormSubmitTriggerFor) == 'undefined'\n && typeof(instance.$forms[id]) != 'undefined'\n && typeof(instance.$forms[id].submitTrigger) == 'undefined'\n && typeof($form[i].form.id) != 'undefined' \n && id == $form[i].form.id\n ) {\n instance.$forms[id].submitTrigger = $form[i].id || $form[i].getAttribute('id');\n // mark submitTrigger\n $form[i].dataset.ginaFormSubmitTriggerFor = id;\n } \n // else, skipping\n }\n \n name = $form[i].getAttribute('name');\n // NB.: If you still want to save the info and you main field is disabled;\n // consider using an input type=hidden of validator rule `\"exclude\" : false`\n isDisabled = $form[i].disabled || $form[i].getAttribute('disabled'); \n isDisabled = ( /disabled|true/i.test(isDisabled) ) ? true : false;\n \n if (!name) continue;\n if (isDisabled) continue;\n\n // TODO - add switch cases against tagName (checkbox/radio)\n if ( \n typeof($form[i].type) != 'undefined'\n && $form[i].type == 'radio' \n || \n typeof($form[i].type) != 'undefined'\n && $form[i].type == 'checkbox' )\n {\n \n if ( \n $form[i].checked \n || typeof (rules[name]) == 'undefined'\n && $form[i].value != 'undefined'\n && /^(true|false)$/.test($form[i].value)\n || !$form[i].checked\n && typeof (rules[name]) != 'undefined'\n //&& typeof (rules[name].isBoolean) != 'undefined' && /^true$/.test(rules[name].isBoolean)\n //&& typeof (rules[name].isRequired) != 'undefined' && /^true$/.test(rules[name].isRequired)\n && typeof (rules[name].isBoolean) != 'undefined'\n && /^(true|false)$/.test($form[i].value)\n ) {\n // if is boolean\n if ( /^(true|false)$/.test($form[i].value) ) {\n \n if ( typeof(rules[name]) == 'undefined' ) {\n rules[name] = { isBoolean: true };\n } else if ( typeof(rules[name]) != 'undefined' && typeof(rules[name].isBoolean) == 'undefined' ) {\n rules[name].isBoolean = true;\n // forces it when field found in validation rules\n rules[name].isRequired = true;\n }\n\n if ($form[i].type == 'radio') {\n if ( typeof(rules[name]) == 'undefined' )\n throw new Error('rule '+ name +' is not defined');\n \n if (/^true$/.test(rules[name].isBoolean) && $form[i].checked ) {\n fields[name] = (/^true$/.test($form[i].value)) ? true : false;\n }\n } else {\n fields[name] = $form[i].value = (/^true$/.test($form[i].value)) ? true : false;\n }\n\n } else {\n fields[name] = $form[i].value\n }\n \n } else if ( // force validator to pass `false` if boolean is required explicitly\n rules\n && typeof(rules[name]) != 'undefined'\n && typeof(rules[name].isBoolean) != 'undefined'\n && typeof(rules[name].isRequired) != 'undefined'\n && !/^(true|false)$/.test($form[i].value)\n\n ) {\n fields[name] = false;\n }\n\n } else {\n fields[name] = $form[i].value;\n }\n\n if ( typeof($fields[name]) == 'undefined' ) {\n $fields[name] = $form[i];\n // reset filed error data attributes\n $fields[name].setAttribute('data-gina-form-errors', '');\n }\n \n //++fields['_length']\n }// EO Parsing form elements\n fields['_length'] = fields.count() || 0;\n \n return {\n '$fields' : $fields,\n 'fields' : fields,\n 'rules' : rules\n }\n }\n \n var getCastedValue = function(ruleObj, fields, fieldName, isOnDynamisedRulesMode) {\n \n if ( \n // do not cast if no rule linked to the field\n typeof(ruleObj[fieldName]) == 'undefined'\n // do not cast if not defined or on error\n || /^(null|NaN|undefined|\\s*)$/i.test(fields[fieldName])\n ) {\n return fields[fieldName]\n }\n \n if ( \n /**typeof(ruleObj[fieldName].isBoolean) != 'undefined'\n || */typeof(ruleObj[fieldName].isNumber) != 'undefined'\n || typeof(ruleObj[fieldName].isInteger) != 'undefined'\n || typeof(ruleObj[fieldName].isFloat) != 'undefined'\n || typeof(ruleObj[fieldName].toFloat) != 'undefined'\n || typeof(ruleObj[fieldName].toInteger) != 'undefined'\n ) {\n \n if ( /\\,/.test(fields[fieldName]) ) {\n fields[fieldName] = fields[fieldName].replace(/\\,/g, '.').replace(/\\s+/g, '');\n }\n return fields[fieldName];\n }\n \n if ( typeof(fields[fieldName]) == 'boolean') {\n return fields[fieldName]\n } else if (ruleObj[fieldName].isBoolean) {\n return (/^true$/i.test(fields[fieldName])) ? true : false;\n }\n \n return (\n typeof(isOnDynamisedRulesMode) != 'undefined' \n && /^true$/i.test(isOnDynamisedRulesMode) \n ) ? '\\\\\"'+ fields[fieldName] +'\\\\\"' : fields[fieldName];\n }\n \n /**\n * formatFields\n * Will cast values if needed\n * \n * @param {string|object} rules \n * @param {object} fields \n * @returns \n */\n var formatFields = function(rules, fields) {\n var ruleObj = null;\n if ( typeof(rules) != 'string') {\n rules = JSON.stringify(JSON.clone(rules))\n }\n ruleObj = JSON.parse(rules.replace(/\\\"(true|false)\\\"/gi, '$1'));\n \n for (let fName in fields) {\n fields[fName] = getCastedValue(ruleObj, fields, fName);\n }\n return fields;\n }\n \n var getDynamisedRules = function(stringifiedRules, fields, $fields, isLiveCheckingOnASingleElement) {\n \n // Because this could also be live check, if it is the case, we need all fields\n // of the current form rule for variables replacement/evaluation. Since live check is\n // meant to validate one field at the time, you could fall in a case where the current\n // field should be compared with another field of the same form.\n var ruleObj = JSON.parse(stringifiedRules.replace(/\\\"(true|false)\\\"/gi, '$1'));\n var stringifiedRulesTmp = JSON.stringify(ruleObj);\n if (isLiveCheckingOnASingleElement) { \n var $currentForm = $fields[Object.getOwnPropertyNames($fields)[0]].form;\n var vInfos = getFormValidationInfos($currentForm, ruleObj);\n delete vInfos.fields._length;\n \n fields = vInfos.fields;\n $fields = vInfos.$fields;\n }\n \n \n var re = null, _field = null, arrFields = [], a = 0;\n // avoiding conflict like [\"myfield\", \"myfield-name\"]\n // where once `myfield` is replaced for exemple with `1234`, you also get 1234-name left behind\n // TODO - Replace this trick with a RegExp matching only the exact word\n // TODO - test this one: \n // \\W(\\$myfield-name)(?!-)\\W\n for (let field in fields) {\n arrFields[a] = field;\n a++;\n }\n arrFields.sort().reverse();\n \n for (let i = 0, len = arrFields.length; i < len; i++) {\n _field = arrFields[i].replace(/\\-|\\_|\\@|\\#|\\.|\\[|\\]/g, '\\\\$&');\n re = new RegExp('\\\\$'+_field, 'g');\n // default field value\n let fieldValue = '\\\\\"'+ fields[arrFields[i]] +'\\\\\"';\n let isInRule = re.test(stringifiedRulesTmp);\n if ( isInRule && typeof(ruleObj[arrFields[i]]) != 'undefined' ) {\n fieldValue = getCastedValue(ruleObj, fields, arrFields[i], true);\n } else if ( isInRule ) {\n console.warn('`'+arrFields[i]+'` is used in a dynamic rule without definition. This could lead to an evaluation error. Casting `'+arrFields[i]+'` to `string`.');\n }\n \n stringifiedRules = stringifiedRules.replace(re, fieldValue );\n }\n if ( /\\$(.*)/.test(stringifiedRules) ) {\n for (let i = 0, len = arrFields.length; i < len; i++) {\n _field = arrFields[i].replace(/\\-|\\_|\\@|\\#|\\.|\\[|\\]/g, '\\\\$&');\n re = new RegExp('\\\\$'+_field, 'g');\n // default field value\n let fieldValue = ($fields[arrFields[i]].value != '' ) ? '\\\\\"'+ $fields[arrFields[i]].value +'\\\\\"' : '\\\\\"\\\\\"';\n let isInRule = re.test(stringifiedRulesTmp);\n if ( isInRule && typeof(ruleObj[arrFields[i]]) != 'undefined' ) {\n fieldValue = getCastedValue(ruleObj, fields, arrFields[i], true);\n } else if ( isInRule ) {\n console.warn('`'+arrFields[i]+'` is used in a dynamic rule without definition. This could lead to an evaluation error. Casting `'+arrFields[i]+'` to `string`.');\n }\n \n stringifiedRules = stringifiedRules.replace(re, fieldValue || $fields[arrFields[i]].checked);\n }\n }\n \n return JSON.parse(stringifiedRules)\n }\n \n \n /**\n * Validate form\n * @param {object} $formOrElement - ${form|element}.target (DOMObject)\n * @param {object} fields \n * @param {object} $fields \n * @param {object} rules \n * @param {callback} cb \n */\n var validate = function($formOrElement, fields, $fields, rules, cb) {\n\n delete fields['_length']; //cleaning\n \n var stringifiedRules = JSON.stringify(rules);\n fields = formatFields(stringifiedRules, fields);\n if ( /\\$(.*)/.test(stringifiedRules) ) {\n var isLiveCheckingOnASingleElement = (\n !/^form$/i.test($formOrElement.tagName)\n && $fields.count() == 1\n && /true/i.test($formOrElement.form.dataset.ginaFormLiveCheckEnabled)\n ) ? true : false;\n rules = getDynamisedRules(stringifiedRules, fields, $fields, isLiveCheckingOnASingleElement)\n }\n var id = null\n , evt = null\n , data = null\n , hasBeenValidated = false\n , subLevelRules = 0\n , rootFieldsCount = fields.count()\n , hasParsedAllRules = false \n , $asyncField = null\n , $asyncFieldId = null\n , asyncEvt = null\n , asyncCount = 0\n ;\n \n \n var re = null, flags = null, args = null; \n var checkFieldAgainstRules = function(field, rules, fields) {\n // ignore field if used as a _case_field\n \n // looking for regexp aliases from rules\n if ( typeof (rules[field]) == 'undefined') { \n skipTest = false;\n // TODO - replace loop by checkForRuleAlias(rules, $el);\n for (var _r in rules) {\n if (/^_comment$/i.test(_r)) continue;\n if ( /^\\//.test(_r) ) { // RegExp found\n re = _r.match(/\\/(.*)\\//).pop(); \n flags = _r.replace('/'+ re +'/', '');\n // fix escaping \"[\" & \"]\"\n re = re.replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]');\n re = new RegExp(re, flags);\n if ( re.test(field) ) { \n skipTest = true; \n // create new entry \n rules[field] = rules[_r]; \n break;\n } \n } \n }\n \n if ( typeof(rules[field]) == 'undefined' )\n return;\n }\n \n var listedFields = Object.getOwnPropertyNames(rules) || [];\n var f = 0, fLen = listedFields.length;\n if (fLen > 0) {\n while (f < fLen) {\n if ( \n typeof(rules[listedFields[f]].exclude) != 'undefined'\n && /^true$/i.test(rules[listedFields[f]].exclude) \n ) {\n // remove from listedFields\n listedFields.splice(f, 1);\n fLen--;\n f--;\n }\n f++;\n }\n }\n \n // check each field against rule\n for (var rule in rules[field]) {\n // skip when not processing rule function\n if ( typeof(d[field][rule]) != 'function' ) {\n continue;\n }\n \n if ( /^((is)\\d+|is$)/.test(rule) && typeof(d[field][rule]) == 'undefined' ) { // is aliases \n d[field][rule] = function(){};\n d[field][rule] = inherits(d[field][rule], d[field][ rule.replace(/\\d+/, '') ]);\n d[field][rule].setAlias = (function(alias) {\n this._currentValidatorAlias = alias\n }(rule)); \n } \n // check for rule params\n try {\n if (Array.isArray(rules[field][rule])) { // has args\n //convert array to arguments\n args = JSON.clone(rules[field][rule]);\n if ( /\\$[\\-\\w\\[\\]]*/.test(args[0]) ) {\n var foundVariables = args[0].match(/\\$[\\-\\w\\[\\]]*/g);\n for (var v = 0, vLen = foundVariables.length; v < vLen; ++v) {\n args[0] = args[0].replace( foundVariables[v], d[foundVariables[v].replace('$', '')].value )\n }\n }\n d[field][rule].apply(d[field], args);\n } else {\n // query rule case\n if ( /^query$/.test(rule) ) {\n $asyncField = $fields[field];\n $asyncFieldId = $asyncField.getAttribute('id');\n asyncEvt = 'asyncCompleted.'+ $asyncFieldId;\n \n var triggeredCount = 0, eventTriggered = false;\n if ( typeof(gina.events[asyncEvt]) != 'undefined' ) { \n console.debug('event `'+ asyncEvt +'` already added');\n asyncCount = 0;\n return;\n }\n ++asyncCount;\n //console.debug('Adding listner '+asyncEvt);\n addListener(gina, $asyncField, asyncEvt, function onasyncCompleted(event) {\n event.preventDefault();\n \n triggeredCount++; \n --asyncCount;\n // is this the last rule ?\n var _rulesArr = Object.getOwnPropertyNames(rules[field]);\n if (_rulesArr[_rulesArr.length-1] == rule) {\n hasParsedAllRules = true;\n }\n \n var _asyncEvt = 'asyncCompleted.' + event.target.getAttribute('id');\n if ( /true/.test(eventTriggered) ) {\n // console.debug('already triggered !\\nasyncCount: '+ asyncCount +'\\nhasParsedAllRules: '+hasParsedAllRules ); \n return;\n }\n \n d[field] = event.detail;\n \n // retrieve current form\n var $currentForm = $formOrElement;\n if ( !/^form$/i.test($formOrElement.tagName) ) {\n $currentForm = $formOrElement.form; \n } \n var formId = $currentForm.getAttribute('id');\n \n if ( \n hasParsedAllRules \n && asyncCount <= 0\n && !eventTriggered\n ) {\n eventTriggered = true;\n \n // removing listner to revalidate with another context\n //console.debug('removing listner '+ _asyncEvt +'\\nasyncCount: '+ asyncCount +'\\nhasParsedAllRules: '+hasParsedAllRules + '\\neventTriggered: '+ eventTriggered);\n removeListener(gina, event.target, _asyncEvt);\n \n cb._data = d['toData']();\n cb._errors = d['getErrors'](field);\n // console.debug('query callbakc triggered ', cb._errors, '\\nisValidating: ', instance.$forms[formId].isValidating);\n // update instance form errors\n if ( cb._errors && cb._errors.count() > 0) {\n if ( typeof(instance.$forms[formId].errors) == 'undefined' ) {\n instance.$forms[formId].errors = {}\n }\n \n instance.$forms[formId].errors[field] = cb._errors[field];\n \n if (!isFormValid && /^true|false$/i.test(instance.$forms[formId].isValidating) || d[field].target.value != '' ) { \n refreshWarning($allFields[field]);\n handleErrorsDisplay($currentForm, cb._errors, cb._data, field);\n updateSubmitTriggerState( $currentForm, isFormValid);\n }\n \n if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) {\n // update toolbar\n if (!gina.forms.errors)\n gina.forms.errors = {};\n \n var objCallback = {\n id : formId,\n errors : instance.$forms[formId].errors || {}\n };\n \n window.ginaToolbar.update('forms', objCallback);\n }\n \n \n triggerEvent(gina, $currentForm, 'validated.' + formId, cb);\n return;\n } \n }\n \n // is this the last or the only field to be validated ?\n var needsGlobalReValidation = false, isFormValid = null;\n if ( listedFields.length == 1 || listedFields[listedFields.length-1] == field) {\n // trigger end of validation\n // console.debug(field +' is the last element to be validated for formId: '+ formId, cb._errors, instance.$forms[formId].errors);\n isFormValid = ( cb._errors.count() > 0 ) ? false : true;\n if (!isFormValid && /^true|false$/i.test(instance.$forms[formId].isValidating)) {\n //console.debug('should update error display now ', cb._errors);\n instance.$forms[formId].errors = merge(cb._errors, instance.$forms[formId].errors);\n refreshWarning($allFields[field]);\n handleErrorsDisplay($currentForm, cb._errors, cb._data, field);\n updateSubmitTriggerState( $currentForm, isFormValid);\n } \n triggerEvent(gina, $currentForm, 'validated.' + formId, cb);\n }\n // just update warning state \n else if (/^true$/i.test(instance.$forms[formId].isValidating) && listedFields.length > 1 && listedFields[listedFields.length-1] != field ) {\n //console.debug(field +' is NOT the last element to be validated for formId: '+ formId);\n needsGlobalReValidation = true; \n }\n \n if (needsGlobalReValidation) {\n validate($currentForm, allFields, $allFields, rules, function onSilentQueryGlobalLiveValidation(gResult){\n instance.$forms[formId].isValidating = false;\n // console.debug('['+ formId +'] onSilentQueryGlobalLiveValidation: '+ gResult.isValid(), gResult);\n isFormValid = gResult.isValid();\n if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) {\n // update toolbar\n if (!gina.forms.errors)\n gina.forms.errors = {};\n \n var objCallback = {\n id : formId,\n errors : gResult.error || {}\n };\n \n window.ginaToolbar.update('forms', objCallback);\n } \n \n \n \n handleErrorsDisplay($currentForm, gResult.error, gResult.data, field);\n updateSubmitTriggerState( $currentForm, isFormValid);\n })\n }\n \n });\n \n d[field][rule](rules[field][rule]);\n continue;\n }\n // normal rule case\n else {\n d[field][rule](rules[field][rule]);\n }\n }\n\n delete fields[field];\n\n } catch (err) {\n if (rule == 'conditions') {\n throw new Error('[ ginaFormValidator ] could not evaluate `' + field + '->' + rule + '()` where `conditions` must be a `collection` (Array)\\nStack:\\n' + err)\n } else {\n throw new Error('[ ginaFormValidator ] could not evaluate `' + field + '->' + rule + '()`\\nStack:\\n' + err)\n }\n }\n }\n }\n \n \n //console.debug(fields, $fields);\n var d = null;//FormValidator instance\n var fieldErrorsAttributes = {}, isSingleElement = false;\n if (isGFFCtx) { // Live check if frontend only for now\n // form case\n if ( /^form$/i.test($formOrElement.tagName) ) {\n id = $formOrElement.getAttribute('id');\n evt = 'validated.' + id;\n instance.$forms[id].fields = fields;\n // clear existing errors\n if ( typeof($formOrElement.eventData) != 'undefined' && typeof($formOrElement.eventData.error) != 'undefined' ) {\n delete $formOrElement.eventData.error\n }\n d = new FormValidator(fields, $fields, xhrOptions);\n }\n // single element case \n else {\n isSingleElement = true;\n id = $formOrElement.form.getAttribute('id') || $formOrElement.form.target.getAttribute('id');\n \n evt = 'validated.' + id;\n instance.$forms[id].fields = fields;\n d = new FormValidator(fields, $fields, xhrOptions, instance.$forms[id].fieldsSet); \n } \n } else {\n d = new FormValidator(fields, null, xhrOptions);\n }\n\n \n var allFields = null;\n var $allFields = null;\n if (!isSingleElement) {\n allFields = JSON.clone(fields);\n $allFields = $fields;\n } else {\n // TODO - Get cached infos\n var formId = $formOrElement.form.getAttribute('id');\n var formAllInfos = getFormValidationInfos(instance.$forms[formId].target, instance.$forms[formId].rules, false); \n allFields = formatFields(JSON.stringify(instance.$forms[formId].rules), JSON.clone(formAllInfos.fields));\n $allFields = formAllInfos.$fields;\n }\n \n var allRules = ( typeof(rules) != 'undefined' ) ? JSON.clone(rules) : {};\n var forEachField = function($formOrElement, allFields, allRules, fields, $fields, rules, cb, i) { \n \n \n var hasCase = false, isInCase = null, conditions = null;\n var caseValue = null, caseType = null;\n var localRules = null, caseName = null;\n var localRuleObj = null, skipTest = null;\n\n //console.debug('parsing ', fields, $fields, rules);\n if ( typeof(rules) != 'undefined' ) {\n \n for (var field in fields) {\n \n if ( isGFFCtx && typeof($fields[field]) == 'undefined' ) {\n //throw new Error('field `'+ field +'` found for your form rule ('+ $formOrElement.id +'), but not found in $field collection.\\nPlease, check your HTML or remove `'+ field +'` declaration from your rule.')\n console.warn('field `'+ field +'` found for your form rule ('+ $formOrElement.id +'), but not found in $field collection.\\nPlease, check your HTML or remove `'+ field +'` declaration from your rule if this is a mistake.');\n continue;\n }\n // 2021-01-17: fixing exclude default override for `data-gina-form-element-group`\n if ( \n isGFFCtx\n && $fields[field].getAttribute('data-gina-form-element-group')\n && typeof(rules[field]) != 'undefined'\n && typeof(rules[field].exclude) != 'undefined'\n && rules[field].exclude\n && !$fields[field].disabled\n ) {\n rules[field].exclude = false;\n }\n \n hasCase = ( typeof(rules['_case_' + field]) != 'undefined' ) ? true : false;\n isInCase = false;\n \n \n if ( \n isGFFCtx\n && $fields[field].tagName.toLowerCase() == 'input' \n && /(checkbox)/i.test($fields[field].getAttribute('type')) \n ) {\n if ( \n !$fields[field].checked\n && typeof(rules[field]) != 'undefined' \n && typeof(rules[field].isRequired) != 'undefined' \n && /^(false)$/i.test(rules[field].isRequired)\n ||\n $fields[field].disabled\n ) { \n rules[field] = {\n exclude: true\n } \n \n } else if ( !$fields[field].checked && typeof(rules[field]) == 'undefined' ) { \n continue;\n }\n }\n \n\n \n \n for (var c in rules) {\n if (!/^\\_case\\_/.test(c) ) continue;\n if ( typeof(rules[c].conditions) == 'undefined' || Array.isArray(rules[c].conditions) && !rules[c].conditions.length ) continue;\n if ( typeof(rules[c].conditions[0].rules) == 'undefined' ) continue;\n \n \n // enter cases conditions\n if ( \n typeof(rules[c].conditions) != 'undefined' \n && Array.isArray(rules[c].conditions) \n ) {\n caseName = c.replace('_case_', ''); \n // if case exists but case field not existing\n if ( typeof($allFields[caseName]) == 'undefined' ) {\n console.warn('Found case `'+ c +'` but field `'+ caseName +'` is misssing in the dom.\\n You should add `'+ caseName +'` element to your form in order to allow Validator to process this case.');\n continue\n }\n \n // depending on the case value, replace/merge original rule with condition rule\n if ( typeof(allFields[caseName]) == 'undefined' ) {\n //allFields[caseName] = $fields[c.replace(/^\\_case\\_/, '')].value\n allFields[caseName] = $allFields[caseName].value\n }\n // Watch changes in case the value is modified\n // A mutation observer was previously defined in case of hidden field when value has been mutated with javascript\n // Ref.: liveCheck; look for comment `// Adding observer for hidden fileds`\n /**\n let caseEvent = 'change._case_' + caseName;\n if ( typeof(gina.events[caseEvent]) == 'undefined' ) {\n \n var redefineRulingContext = function($el, rules, c) {\n var _caseName = $el.name;\n if ( allFields[_caseName] != $el.value ) {\n console.debug('case `'+ _caseName +'` is changing from ', allFields[_caseName], ' to ', $el.value );\n \n if ( typeof(fields) == 'undefined') {\n var fields = {};\n }\n var _val = $el.value;\n if ( /^(true|false)$/i.test(_val) ) {\n _val = (/^(true)$/i.test(_val)) ? true : false;\n } \n if ( /^\\d+$/.test(_val) ) {\n _val = parseInt(_val);\n }\n // Saving case current value\n allFields[_caseName] = fields[_caseName] = _val;\n \n // rebind & restart validation in silent mode\n var $_form = $el.form;\n if ($_form) {\n // backup `originalRules` in order to avoid override\n var formInstance = instance['$forms'][$_form.id];\n var customRules = {};\n var caseRules = {};\n var _conditions = [];\n if ( typeof(formInstance.originaRules) == 'undefined' ) {\n formInstance.originaRules = JSON.clone(rules);\n } else {\n //customRules = merge(rules, formInstance.originaRules);\n //customRules = JSON.clone(formInstance.originaRules);\n caseRules = JSON.clone(formInstance.originaRules);\n }\n //var customRules = JSON.clone(formInstance.originaRules);\n \n //var customRules = JSON.clone(rules);\n \n if ( typeof(rules[c]) != 'undefined' && typeof(rules[c].conditions) != 'undefined' ) {\n _conditions = rules[c].conditions;\n } else if (typeof(rules['_case_'+_caseName]) != 'undefined' && typeof(rules['_case_'+_caseName].conditions) != 'undefined') {\n _conditions = rules['_case_'+_caseName].conditions;\n }\n if (_conditions.length > 1) { // more than one condition\n for (let _ci = 0, _ciLen = _conditions.length; _ci < _ciLen; _ci++) {\n if ( \n Array.isArray(_conditions[_ci].case)\n && _conditions[_ci].case.indexOf(fields[_caseName]) > -1\n ||\n _conditions[_ci].case == fields[_caseName]\n ) {\n // Inherited first\n caseRules = merge(_conditions[_ci].rules, caseRules);\n //caseRules = _conditions[_ci].rules;\n }\n } \n } else {\n if ( \n Array.isArray(_conditions[0].case)\n && _conditions[0].case.indexOf(fields[_caseName]) > -1\n ||\n _conditions[0].case == fields[_caseName]\n ) {\n // Inherited first\n caseRules = merge(_conditions[0].rules, caseRules);\n //caseRules = _conditions[0].rules;\n } else {\n var _filter = {};\n _filter['case'] = fields[_caseName];\n try {\n caseRules = merge(new Collection(_conditions).findOne(_filter).rules, caseRules)\n //caseRules = new Collection(_conditions).findOne(_filter).rules\n //caseRules = new Collection(_conditions).findOne(_filter).rules;\n } catch (err) {\n console.warn('Trying to eval undeclared or misconfigured case `\"_case_'+ _caseName +'\"`: `'+ fields[_caseName] +'`.\\Now Skipping it, please check your rules and fix it if needed.');\n // else -> caseRules = {}\n }\n \n _filter = null;\n } \n }\n _conditions = null;\n \n \n \n // Setting up new validation rules\n for (let _f in caseRules) {\n // if ( typeof(customRules[_f]) == 'undefined' ) {\n customRules[_f] = caseRules[_f];\n // } else {\n // // do not override customRules\n // customRules[_f] = merge(customRules[_f], caseRules[_f]);\n // }\n \n }\n // formInstance._current_caseName = _caseName;\n // if ( typeof(formInstance._current_case) == 'undefined' ) {\n // formInstance._current_case = {};\n // }\n // formInstance._current_case[_caseName] = customRules;\n \n caseRules = null;\n // reset binding\n reBindForm($_form, customRules);\n }\n }\n }\n \n \n //console.debug('placing event on ', $fields[caseName].name, caseEvent)\n // We need to bind the case event and the input event at the same time \n // search for grouped els\n // var grpName = $fields[caseName].name;\n // var selectedEls = [], sl = 0;\n // if ( $formOrElement.length > 1 ) {\n // for (let g = 0, gLen = $formOrElement.length; g < gLen; g++) {\n // if ( \n // $formOrElement[g].name == grpName\n // && $formOrElement[g].type == $fields[caseName].type\n // && $formOrElement[g].id != $fields[caseName].id\n // ) {\n // selectedEls[sl] = $formOrElement[g];\n // ++sl;\n // }\n // }\n // } \n // This portion of code is used for case value change\n // var $elementToBind = (selectedEls.length > 0) ? selectedEls : $fields[caseName]; \n // addListener(gina, $elementToBind, 'change.', function(event) {\n // event.preventDefault();\n // console.debug('Now rebinding on ', event.currentTarget.name +' == '+ event.currentTarget.value );\n // redefineRulingContext(event.currentTarget, rules, c);\n // });\n \n // handles _case_* change; also useful if your are using radio tabs as cases triggers\n addListener(gina, $fields[caseName], [ caseEvent, 'change.'+$fields[caseName].id ], function(event) {\n event.preventDefault();\n console.debug('First rebinding on ', event.currentTarget.name +' == '+ event.currentTarget.value );\n redefineRulingContext(event.currentTarget, rules, c);\n });\n \n } // EO caseEvent\n */\n caseValue = allFields[caseName];\n if (isGFFCtx) {\n if (fields[field] == \"true\")\n caseValue = true;\n else if (fields[field] == \"false\")\n caseValue = false;\n }\n \n \n // filtering conditions\n for (var _c = 0, _cLen = rules[c].conditions.length; _c < _cLen; ++_c) {\n \n if (rules[c].conditions[_c].case != caseValue) {\n continue;\n }\n \n // enter condition rules\n for (var _r in rules[c].conditions[_c].rules) {\n if (/^_comment$/i.test(_r)) continue;\n // ignore if we are testing on caseField or if $field does not exist\n if (_r == caseName || !$fields[_r]) continue;\n //if (_r == caseName || !$fields[caseName]) continue;\n // ok, not the current case but still, \n // we want to apply the validation when the field is not yet listed \n if (field != _r && !/^\\//.test(_r) ) {\n if ( \n typeof(fields[_r]) == 'undefined' \n && typeof(allFields[_r]) != 'undefined' \n ) {\n fields[_r] = allFields[_r];\n localRuleObj = ( typeof(rules[_r]) != 'undefined' ) ? rules[_r] : {}; \n rules[_r] = merge(rules[c].conditions[_c].rules[_r], localRuleObj);\n \n checkFieldAgainstRules(_r, rules, fields);\n continue;\n }\n }\n \n \n if ( /^\\//.test(_r) ) { // RegExp found\n re = _r.match(/\\/(.*)\\//).pop(); \n flags = _r.replace('/'+ re +'/', '');\n // fix escaping \"[\" & \"]\"\n re = re.replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]');\n re = new RegExp(re, flags);\n if ( re.test(field) ) { \n // depending on the case value, replace/merge original rule with condition rule\n // if ( typeof(allFields[caseField]) == 'undefined' ) {\n // allFields[caseField] = $fields[c.replace(/^\\_case\\_/, '')].value\n // }\n // caseValue = allFields[caseField];\n // if (isGFFCtx) {\n // if (fields[field] == \"true\")\n // caseValue = true;\n // else if (fields[field] == \"false\")\n // caseValue = false;\n // }\n if ( \n rules[c].conditions[_c].case == caseValue \n ||\n // test for regexp \n /^\\//.test(rules[c].conditions[_c].case) \n && new RegExp(rules[c].conditions[_c].case).test(caseValue) \n ) {\n localRuleObj = ( typeof(rules[_r]) != 'undefined' ) ? rules[_r] : {}; \n rules[_r] = merge(rules[c].conditions[_c].rules[_r], localRuleObj);\n }\n // check each field against rule only if rule exists 1/3\n if ( caseName != _r && typeof(rules[_r]) != 'undefined') {\n checkFieldAgainstRules(_r, rules, fields);\n }\n } \n } else {\n if ( typeof(rules[c].conditions[_c].rules[_r]) != 'undefined' ) {\n // depending on the case value, replace/merge original rule with condition rule\n //caseField = c.replace(/^\\_case\\_/, '');\n caseField = _r;\n caseValue = fields[caseField];\n \n if ( typeof($fields[caseField]) == 'undefined' ) {\n console.warn('ignoring case `'+ caseField +'`: field `'+ +'` not found in your DOM');\n continue;\n }\n // by default\n // if ( typeof(allFields[caseField]) == 'undefined' ) {\n // allFields[caseField] = $fields[caseField].value\n // }\n // caseValue = allFields[caseField];\n // boolean caseValue\n if (\n isGFFCtx \n && /^(true|false)$/i.test(caseValue) \n && typeof(rules[caseField]) != 'undefined'\n && typeof(rules[caseField].isBoolean) != 'undefined' \n && /^(true)$/i.test(rules[caseField].isBoolean)\n ) {\n caseValue = ( /^(true)$/i.test(caseValue) ) ? true : false;\n }\n \n if ( \n //rules[c].conditions[_c].case == caseValue \n typeof(rules[c].conditions[_c].rules[_r]) != 'undefined'\n // ||\n // // test for regexp \n // /^\\//.test(rules[c].conditions[_c].case) \n // && new RegExp(rules[c].conditions[_c].case).test(caseValue)\n ) {\n localRuleObj = ( typeof(rules[c].conditions[_c].rules[_r]) != 'undefined' ) ? rules[c].conditions[_c].rules[_r] : {};\n //rules[_r] = merge(rules[c].conditions[_c].rules[_r], localRuleObj);\n rules[_r] = localRuleObj;\n }\n \n // check each field against rule only if rule exists 2/3\n //if ( caseName != _r && typeof(rules[_r]) != 'undefined' ) {\n if ( caseName != _r && typeof(rules[_r]) != 'undefined' && typeof(fields[_r]) != 'undefined' ) {\n checkFieldAgainstRules(_r, rules, fields);\n }\n } \n }\n }\n }\n } \n }\n \n if (isInCase || caseName == field) continue; \n\n // check each field against rule only if rule exists 3/3\n if ( typeof(rules[field]) != 'undefined' ) {\n //checkFieldAgainstRules(field, rules, fields);\n checkFieldAgainstRules(field, rules, allFields);\n } \n \n if (hasCase) {\n ++i; // add sub level\n conditions = rules['_case_' + field]['conditions'];\n\n if ( !conditions ) {\n throw new Error('[ ginaFormValidator ] case `_case_'+field+'` found without `condition(s)` !\\nPlease, check your delcaration for `_case_'+ field +'`');\n }\n \n \n for (var c = 0, cLen = conditions.length; c<cLen; ++c) {\n // by default\n //caseValue = fields[field];\n caseValue = allFields[field];\n\n if (isGFFCtx) {\n if (fields[field] == \"true\")\n caseValue = true;\n else if (fields[field] == \"false\")\n caseValue = false;\n }\n\n //console.debug(caseValue +' VS '+ conditions[c]['case'], \"->\", (caseValue == conditions[c]['case'] || Array.isArray(conditions[c]['case']) && conditions[c]['case'].indexOf(caseValue) > -1) );\n if ( \n conditions[c]['case'] === caseValue \n ||\n Array.isArray(conditions[c]['case']) && conditions[c]['case'].indexOf(caseValue) > -1 \n ||\n /^\\//.test(conditions[c]['case']) \n ) {\n\n //console.debug('[fields ] ' + JSON.stringify(fields, null, 4));\n localRules = {}; \n // exclude case field if not declared in rules && not disabled\n if ( \n typeof(conditions[c]['rules'][field]) == 'undefined' \n && typeof(allFields[field]) == 'undefined'\n ||\n $fields[field].disabled \n ) {\n conditions[c]['rules'][field] = { exclude: true } \n } \n for (var f in conditions[c]['rules']) {\n if (/^_comment$/i.test(f)) continue;\n //console.debug('F: ', f, '\\nrule: '+ JSON.stringify(conditions[c]['rules'][f], null, 2));\n if ( /^\\//.test(f) ) { // RegExp found\n\n re = f.match(/\\/(.*)\\//).pop(); \n flags = f.replace('/'+ re +'/', '');\n // fix escaping \"[\" & \"]\"\n re = re.replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]');\n re = new RegExp(re, flags);\n\n for (var localField in $fields) {\n if ( re.test(localField) ) {\n if ( /^\\//.test(conditions[c]['case']) ) {\n re = conditions[c]['case'].match(/\\/(.*)\\//).pop();\n flags = conditions[c]['case'].replace('/'+ re +'/', '');\n re = new RegExp(re, flags);\n\n if ( re.test(caseValue) ) {\n localRules[localField] = conditions[c]['rules'][f]; \n }\n\n } else {\n localRules[localField] = conditions[c]['rules'][f]\n }\n \n // we need to add it to fields list if not declared\n if ( \n typeof(fields[localField]) == 'undefined' \n && typeof($fields[localField]) != 'undefined' \n && typeof($fields[localField].value) != 'undefined'\n ) {\n fields[localField] = $fields[localField].value;//caseValue is not goo here\n if (isGFFCtx && /(true|false)/i.test(fields[localField] ) ) {\n if (fields[localField] == \"true\")\n fields[localField] = true;\n else if (fields[localField] == \"false\")\n fields[localField] = false;\n }\n d.addField(localField, fields[localField]);\n if ( typeof(allRules[localField]) != 'undefined' ) {\n localRules[localField] = merge(localRules[localField], allRules[localField])\n }\n }\n }\n }\n\n } else {\n if ( /^\\//.test(conditions[c]['case']) ) {\n \n re = conditions[c]['case'].match(/\\/(.*)\\//).pop(); \n flags = conditions[c]['case'].replace('/'+ re +'/', '');\n // fix escaping \"[\" & \"]\"\n re = re.replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]');\n re = new RegExp(re, flags);\n\n if ( re.test(caseValue) ) {\n localRules[f] = conditions[c]['rules'][f]\n }\n\n } else {\n localRules[f] = conditions[c]['rules'][f]\n }\n \n // we need to add it to fields list if not declared\n // if ( typeof(fields[f]) == 'undefined' ) {\n // fields[f] = caseValue;\n // }\n if ( \n typeof(fields[f]) == 'undefined' \n && typeof($fields[f]) != 'undefined' \n && typeof($fields[f].value) != 'undefined'\n ) {\n fields[f] = $fields[f].value;\n if (isGFFCtx && /(true|false)/i.test(fields[f] ) ) {\n if (fields[f] == \"true\")\n fields[f] = true;\n else if (fields[f] == \"false\")\n fields[f] = false;\n } \n \n d.addField(f, fields[f]);\n if ( typeof(allRules[f]) != 'undefined' ) {\n localRules[f] = merge(localRules[f], allRules[f])\n }\n }\n } \n }\n \n \n \n ++subLevelRules; // add sub level\n if (isGFFCtx)\n forEachField($formOrElement, allFields, allRules, fields, $fields, localRules, cb, i);\n else\n return forEachField($formOrElement, allFields, allRules, fields, $fields, localRules, cb, i);\n }\n \n }\n --i;\n }\n\n \n } // EO for\n } \n \n --subLevelRules;\n\n if (i <= 0 && subLevelRules < 0) {\n \n var errors = d['getErrors']();\n // adding data attribute to handle display refresh\n for (var field in errors) {\n for (rule in errors[field]) {\n if (!fieldErrorsAttributes[field]) {\n fieldErrorsAttributes[field] = ''\n }\n\n if (fieldErrorsAttributes[field].indexOf(rule) < 0)\n fieldErrorsAttributes[field] += rule +' ';\n }\n\n if (isGFFCtx)\n $fields[field].setAttribute('data-gina-form-errors', fieldErrorsAttributes[field].substr(0, fieldErrorsAttributes[field].length-1))\n }\n\n //calling back\n try {\n data = formatData( d['toData']() );\n\n if ( GINA_ENV_IS_DEV && isGFFCtx && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar ) {\n // update toolbar\n if (!gina.forms.validated)\n gina.forms.validated = {};\n \n if (!gina.forms.validated[id])\n gina.forms.validated[id] = {};\n\n var objCallback = {\n id : id,\n validated : data\n };\n\n window.ginaToolbar.update('forms', objCallback);\n }\n } catch (err) {\n throw err\n }\n hasParsedAllRules = true;\n if (!hasBeenValidated && asyncCount <= 0) {\n if ( typeof(cb) != 'undefined' && typeof(cb) === 'function' ) {\n cb._errors = d['getErrors']();\n cb._data = d['toData']();\n triggerEvent(gina, $formOrElement, 'validated.' + id, cb);\n } else {\n hasBeenValidated = true;\n return {\n 'isValid' : d['isValid'],\n 'error' : errors,\n 'data' : data\n }\n }\n }\n }\n }\n \n \n if (isGFFCtx) {\n addListener(gina, $formOrElement, evt, function(event) {\n event.preventDefault();\n \n if (!hasBeenValidated) {\n hasBeenValidated = true;\n hasParsedAllRules = false;\n asyncCount = 0;\n \n var _cb = event.detail;\n var _data = _cb._data || d['toData']();\n var cbErrors = _cb._errors || d['getErrors']() || null;\n \n console.debug('instance errors: ', instance.$forms[id].errors, ' VS cbErrors: ', cbErrors, d['isValid'](), ' VS d.getErrors(): ',d['getErrors']() );\n \n if ( cbErrors.count() > 0 && d['isValid']()) {\n d['isValid'] = function() {\n return false;\n }\n }\n \n _cb({\n 'isValid' : d['isValid'],\n 'error' : cbErrors,\n 'data' : formatData( _data )\n });\n removeListener(gina, event.target, 'validated.' + event.target.id);\n return \n } \n });\n }\n \n // 0 is the starting level\n if (isGFFCtx)\n forEachField($formOrElement, allFields, allRules, fields, $fields, rules, cb, 0);\n else\n return forEachField($formOrElement, allFields, allRules, fields, $fields, rules, cb, 0);\n }\n\n var setupInstanceProto = function() {\n\n instance.target = document;\n instance.setOptions = setOptions;\n instance.getFormById = getFormById;\n instance.validateFormById = validateFormById;\n instance.resetErrorsDisplay = resetErrorsDisplay;\n instance.resetFields = resetFields;\n instance.handleErrorsDisplay = handleErrorsDisplay;\n instance.send = send;\n //instance.handleXhrResponse = handleXhrResponse;\n }\n\n if (isGFFCtx) {\n return init(rules)\n } else {\n return backendInit(rules, data, formId)\n }\n\n};\n\nif ( ( typeof(module) !== 'undefined' ) && module.exports ) {\n // Publish as node.js module\n module.exports = ValidatorPlugin\n} else if ( typeof(define) === 'function' && define.amd) {\n // Publish as AMD module\n define('gina/validator', ['utils/events', 'utils/dom', 'utils/form-validator'], function(){ return ValidatorPlugin })\n};\n",
@@ -50,7 +50,7 @@
50
50
  "define('gina/popin', [ 'require', 'jquery', 'vendor/uuid','utils/merge', 'utils/routing', 'utils/events' ], function (require) {\n\n var $ = require('jquery');\n $.noConflict();\n var uuid = require('vendor/uuid');\n var merge = require('utils/merge');\n var routing = require('utils/routing');\n\n require('utils/events'); // events\n\n /**\n * Gina Popin Handler\n *\n * @param {object} options\n * */\n function Popin(options) {\n\n this.plugin = 'popin';\n\n var events = ['init', 'loaded', 'ready', 'open', 'close', 'click', 'destroy', 'success', 'error', 'progress'];\n registerEvents(this.plugin, events);\n\n var self = { // local use only\n 'options' : {\n 'name' : undefined,\n 'class': 'gina-popin-default'\n },\n authorizedEvents : ['ready', 'error'],\n events: {}\n };\n\n var instance = {\n plugin : this.plugin,\n id : 'gina-popins-' + uuid.v4(),\n on : on,\n eventData : {},\n\n '$popins' : {},\n activePopinId : null, \n getActivePopin : null, // returns the active $popin\n target : document, // by default\n isReady : false,\n initialized : false\n };\n\n // popin proto\n var $popin = { // is on main `gina-popins` container (first level)\n 'plugin' : this.plugin,\n 'on' : on,\n 'eventData' : {},\n 'target' : document, // by default\n\n 'name' : null,\n 'load' : null,\n 'loadContent' : null,\n 'open' : null,\n 'isOpen' : false,\n 'isRedirecting' : false,\n 'close' : null,\n '$forms' : [],\n 'hasForm' : false,\n '$headers' : [] // head elements for this popin\n };\n\n // imopring other plugins\n var $validatorInstance = null; // validator instance\n\n\n // XML Request\n var xhr = null;\n\n var registeredPopins = [];\n\n\n /**\n * popinCreateContainer\n *\n * Creates HTML container and add it to the DOM\n *\n *\n * */\n var popinCreateContainer = function() {\n\n // creating template\n // <div class=\"gina-popins\">\n // <div class=\"gina-popins-overlay gina-popin-is-active\"></div>\n // </div>\n var $container = document.createElement('div');\n $container.id = instance.id;\n $container.setAttribute('id', instance.id);\n $container.setAttribute('class', 'gina-popins');\n\n var $overlay = document.createElement('div');\n $overlay.setAttribute('id', 'gina-popins-overlay');\n $overlay.setAttribute('class', 'gina-popins-overlay');\n\n\n $container.appendChild( $overlay );\n\n // adding to DOM\n document.body.appendChild($container);\n\n instance.target = $container;\n instance.on = on;\n\n gina.popinContainer = instance.id;\n //gina.hasPopinHandler = true;\n }\n \n var popinGetContainer = function () {\n instance.target = document.getElementById(gina.popinContainer);\n instance.on = on;\n }\n\n var proxyClick = function($childNode, $el, evt) {\n //if ( )\n addListener(gina, $childNode, 'click', function(e) {\n cancelEvent(e);\n\n triggerEvent(gina, $el, evt);\n });\n }\n \n var getPopinById = function(id) { \n return ( typeof(instance.$popins[id]) != 'undefined' ) ? instance.$popins[id] : null;\n }\n \n var getPopinByName = function(name) {\n \n var $popin = null;\n \n for (var p in instance.$popins) {\n if ( instance.$popins[p].name === name ) {\n $popin = instance.$popins[p];\n break;\n }\n }\n \n return $popin;\n } \n \n function getActivePopin() { \n var $popin = null;\n \n for (var p in gina.popin.$popins) {\n if ( typeof(gina.popin.$popins[p].isOpen) != 'undefined' && gina.popin.$popins[p].isOpen ) {\n $popin = gina.popin.$popins[p];\n break;\n }\n }\n \n if (!$popin && gina.popin.activePopinId) {\n $popin = gina.popin.$popins[gina.popin.activePopinId]\n }\n \n return $popin;\n } \n \n\n var bindOpen = function($popin, isRouting) {\n \n isRouting = ( typeof(isRouting) != 'undefined' ) ? isRouting : false;\n \n var attr = 'data-gina-popin-name';\n var $els = getElementsByAttribute(attr);\n var $el = null, name = null;\n var url = null; \n var proceed = null, evt = null;\n var i = null, len = null;\n\n i = 0; len = $els.length;\n for (;i < len; ++i) {\n $el = $els[i];\n name = $el.getAttribute(attr);\n if ( $el.tagName == 'A' ) {\n url = $el.getAttribute('href');\n if (url == '' || url =='#' || /\\#/.test(url) ) {\n url = null\n }\n }\n\n if ( !url && typeof( $el.getAttribute('data-gina-popin-url') ) != 'undefined') {\n url = $el.getAttribute('data-gina-popin-url');\n }\n\n if (!url) {\n throw new Error('Found `data-gina-popin-name` without `url` !')\n }\n\n if ( !$el['url'] ) {\n $el['url'] = url;\n }\n\n if ( !$el['popinName'] ) {\n $el['popinName'] = name;\n }\n\n if (name == $popin.name) {\n evt = 'popin.click.'+ 'gina-popin-' + instance.id +'-'+ uuid.v4() +'-'+ name;\n $el['id'] = evt;\n $el.setAttribute( 'id', evt);\n \n if (!gina.events[evt]) {\n \n // attach click events\n addListener(gina, $el, evt, function(e) {\n cancelEvent(e);\n\n var fired = false;\n addListener(gina, $popin.target, 'loaded.'+$popin.id, function(e) {\n e.preventDefault();\n\n if (!fired) {\n fired = true;\n console.debug('active popin should be ', $popin.id);\n gina.popin.activePopinId = $popin.id;\n popinBind(e, $popin);\n if (!$popin.isOpen) { \n popinOpen($popin.name);\n } \n }\n });\n\n // loading & binding popin \n // Non-Preflighted requests\n var options = { \n isSynchrone: false,\n withCredentials: false // by default\n }; \n options = merge($popin.options, options); \n var url = this.getAttribute('data-gina-popin-url') || this.getAttribute('href');\n if (!url) {\n throw new Error('Popin `url` not defined, please check value for `data-gina-popin-url`');\n }\n popinLoad($popin.name, url, options);\n });\n\n\n\n // bind child elements\n var childNodes = $el.childNodes;\n var l = 0; lLen = childNodes.length;\n if (lLen > 0) {\n for(; l < lLen; ++l) {\n if (typeof (childNodes[l].tagName) != 'undefined') {\n proxyClick(childNodes[l], $el, evt)\n }\n }\n }\n }\n }\n\n }\n\n // proxies\n // click on main document\n evt = 'click';// click proxy\n // for proxies, use popinInstance.id as target is always `document`\n addListener(gina, document, evt, function(event) {\n \n if ( event.target.getAttribute('disabled') != null && event.target.getAttribute('disabled') != 'false' ) {\n return false;\n }\n\n if ( typeof(event.target.id) == 'undefined' ) {\n event.target.setAttribute('id', evt +'.'+ uuid.v4() );\n event.target.id = event.target.getAttribute('id')\n }\n\n if ( /^popin\\.close\\./.test(event.target.id) ) {\n cancelEvent(event);\n\n var _evt = event.target.id;\n triggerEvent(gina, event.target, _evt, event.detail);\n }\n\n if ( /^popin\\.click\\./.test(event.target.id) ) {\n cancelEvent(event);\n //console.log('popin.click !! ', event.target);\n var _evt = event.target.id; \n\n if ( new RegExp( '^popin.click.gina-popin-' + instance.id).test(_evt) )\n triggerEvent(gina, event.target, _evt, event.detail);\n }\n });\n\n gina.popinIsBinded = false\n }\n \n \n function popinBind(e, $popin) {\n \n var $el = e.target;\n var eventType = e.type;\n \n if ( \n typeof(e.detail) != 'undefined' \n && typeof(e.detail.trim) == 'function' \n ) {\n $el.innerHTML = e.detail.trim();\n }\n \n \n var register = function (type, evt, $element) {\n var isLink = $element.getAttribute('data-gina-popin-is-link');\n isLink = ( /^true$/i.test(isLink) ) ? true : false;\n if ( type == 'link' && !isLink) {\n // like a form action, so gina will not follow the href and the event will be prevented\n type = 'action';\n }\n // attach submit events\n addListener(gina, $element, evt, function(event) {\n\n cancelEvent(event);\n \n if (type != 'close') {\n \n var fired = false;\n var _evt = 'loaded.' + $popin.id;\n \n if ( typeof(gina.events[_evt]) == 'undefined' ) {\n addListener(gina, $el, _evt, function(e) {\n \n e.preventDefault();\n\n if (!fired) {\n fired = true; \n popinLoadContent(e.detail); \n }\n });\n }\n \n // Non-Preflighted requests\n var options = { \n isSynchrone: false,\n withCredentials: false\n };\n //options = merge(options, $popin.options); \n options = merge($popin.options, options); \n popinLoad($popin.name, $element.href, options);\n } \n \n removeListener(gina, event.target, event.type)\n });\n \n addListener(gina, $element, 'click', function(event) {\n cancelEvent(event);\n // ignore disabled\n if ( event.target.getAttribute('disabled') != null && event.target.getAttribute('disabled') != 'false' ) {\n return false;\n }\n // NB.: `type == 'action'` will be handled by the form validator\n if ( type == 'link' ) {\n //console.debug('This is a link', event.target);\n var linkTarget = event.target.getAttribute('target');\n if ( linkTarget != null && linkTarget != '' ) { \n var _window = window.open(linkHref, event.target.getAttribute('target'));\n // _window.onload = function onWindowLoad() {\n // var $popin = getActivePopin(); \n // triggerEvent(gina, $popin, 'loaded.' + id);\n // }\n } else { // else, inside viewbox\n // TODO - Integrate https://github.com/box/viewer.js#loading-a-simple-viewer \n triggerEvent(gina, event.target, event.currentTarget.id, $popin);\n }\n \n } /**else if ( type == 'action' ) {\n // rewrite form attributes\n //console.debug('This is an action ', event.target);\n }*/ else { // close\n \n if ( typeof(event.target.id) == 'undefined' ) {\n event.target.setAttribute('id', evt +'.'+ uuid.v4() );\n event.target.id = event.target.getAttribute('id')\n }\n \n if ( /^popin\\.close\\./.test(event.target.id) ) {\n cancelEvent(event);\n // Just in case we left the popin with a link:target = _blank\n $popin.isRedirecting = false;\n popinClose($popin.name);\n }\n \n if ( /^popin\\.click\\./.test(event.target.id) ) {\n cancelEvent(event);\n var _evt = event.target.id;\n \n if ( new RegExp( '^popin.click.gina-popin-' + instance.id).test(_evt) )\n triggerEvent(gina, event.target, _evt, event.detail);\n \n }\n } \n });\n \n };\n \n gina.popinIsBinded = true;\n \n var i = null\n , b = null\n , len = null\n ;\n // bind overlay on click\n if (!$popin.isOpen) { \n \n var $overlay = instance.target.childNodes[0];\n addListener(gina, $overlay, 'mousedown', function(event) {\n\n // don't cancel here, it will corrupt child elements behaviors such as checkboxes and radio buttons\n if ( /gina-popin-is-active/.test(event.target.className) ) {\n\n // remove listeners\n removeListener(gina, event.target, 'mousedown');\n \n // binding popin close\n var $close = []\n , $buttonsTMP = [] \n ;\n \n i = 0; \n $buttonsTMP = $el.getElementsByTagName('button');\n b = 0; len = $buttonsTMP.length;\n if ( len > 0 ) {\n for(; b < len; ++b) {\n if ( /gina-popin-close/.test($buttonsTMP[b].className) ) {\n $close[i] = $buttonsTMP[b];\n ++i;\n } \n }\n }\n \n $buttonsTMP = $el.getElementsByTagName('div');\n b = 0; len = $buttonsTMP.length;\n if ( len > 0 ) {\n for(; b < len; ++b) {\n if ( /gina-popin-close/.test($buttonsTMP[b].className) ) {\n $close[i] = $buttonsTMP[b];\n ++i\n } \n }\n }\n \n $buttonsTMP = $el.getElementsByTagName('a');\n b = 0; len = $buttonsTMP.length;\n if ( len > 0 ) {\n for(; b < len; ++b) {\n if ( /gina-popin-close/.test($buttonsTMP[b].className) ) {\n $close[i] = $buttonsTMP[b];\n ++i\n } \n }\n }\n \n b = 0; len = $close.length;\n for (; b < len; ++b) {\n let $el = $close[b];\n let eId = $el.getAttribute('id');\n for (let e = 0, eLen = events.length; e < eLen; e++) {\n let evt = events[e];\n if ( typeof(gina.events[ evt ]) != 'undefined' && gina.events[ evt ] == eId ) {\n removeListener(gina, $el, evt);\n }\n if ( typeof(gina.events[ eId ]) != 'undefined' && gina.events[ eId ] == eId ) { \n removeListener(gina, $el, eId);\n }\n \n if ( typeof(gina.events[ evt +'.'+ eId ]) != 'undefined' && gina.events[ evt +'.'+ eId ] == eId ) {\n removeListener(gina, $el, evt +'.'+ eId);\n }\n \n if ( typeof(gina.events[ evt +'.'+ eId ]) != 'undefined' && gina.events[ evt +'.'+ eId ] == evt +'.'+ eId ) {\n removeListener(gina, $el, evt +'.'+ eId);\n }\n }\n \n \n //removeListener(gina, $close[b], $close[b].getAttribute('id') );\n }\n \n // div with click\n // var $elTMP = $form.target.getElementsByTagName('div');\n // if ( $elTMP.length > 0 ) {\n // for(let i = 0, len = $elTMP.length; i < len; ++i) {\n // $els.push( $elTMP[i] )\n // }\n // }\n // // label with click\n // $elTMP = $form.target.getElementsByTagName('label');\n // if ( $elTMP.length > 0 ) {\n // for(let i = 0, len = $elTMP.length; i < len; ++i) {\n // $els.push( $elTMP[i] )\n // }\n // }\n \n // Just in case we left the popin with a link:target = _blank\n $popin.isRedirecting = false;\n popinClose($popin.name);\n }\n \n });\n }\n // detecting form in popin\n if ( /<form/i.test($el.innerHTML) && typeof($validatorInstance) != 'undefined' && $validatorInstance ) {\n $popin.hasForm = true;\n }\n \n // binding popin close & links (& its target attributes)\n var $close = []\n , $buttonsTMP = []\n , $link = []\n ;\n\n $buttonsTMP = $el.getElementsByTagName('button');\n i = 0; b = 0; len = $buttonsTMP.length;\n if ( $buttonsTMP.length > 0 ) {\n for(; b < len; ++b) {\n if ( /gina-popin-close/.test($buttonsTMP[b].className) ) {\n $close[i] = $buttonsTMP[b];\n ++i\n } \n }\n }\n\n $buttonsTMP = $el.getElementsByTagName('div');\n b = 0; len = $buttonsTMP.length;\n if ( len > 0 ) {\n for(; b < len; ++b) {\n if ( /gina-popin-close/.test($buttonsTMP[b].className) ) {\n $close[i] = $buttonsTMP[b];\n ++i;\n } \n }\n }\n\n $buttonsTMP = $el.getElementsByTagName('a');\n b = 0; len = $buttonsTMP.length;\n if ( len > 0 ) {\n for(; b < len; ++b) {\n if ( /gina-popin-close/.test($buttonsTMP[b].className) ) {\n $close[i] = $buttonsTMP[b];\n ++i;\n continue\n }\n \n if ( \n typeof($buttonsTMP[b]) != 'undefined' \n && !/(\\#|\\#.*)$/.test($buttonsTMP[b].href) // ignore href=\"#\" \n // ignore href already bindded byr formValidator or the user \n && !$buttonsTMP[b].id\n ||\n typeof($buttonsTMP[b]) != 'undefined'\n && !/(\\#|\\#.*)$/.test($buttonsTMP[b].href) // ignore href=\"#\" \n && !/^(click\\.|popin\\.link)/.test($buttonsTMP[b].id)\n ) {\n $link.push($buttonsTMP[b]);\n continue\n }\n }\n }\n \n var onclickAttribute = null, evt = null;\n // close events\n b = 0; len = $close.length;\n for (; b < len; ++b) {\n if ($close[b].tagName == 'A') {\n onclickAttribute = $close[b].getAttribute('onclick');\n }\n\n if ( !onclickAttribute ) {\n $close[b].setAttribute('onclick', 'return false;')\n } else if ( typeof(onclickAttribute) != 'undefined' && !/return false/.test(onclickAttribute) ) {\n if ( /\\;$/.test(onclickAttribute) ) {\n onclickAttribute += 'return false;'\n } else {\n onclickAttribute += '; return false;'\n }\n }\n\n if (!$close[b]['id']) {\n\n evt = 'popin.close.'+ uuid.v4();\n $close[b]['id'] = evt;\n $close[b].setAttribute( 'id', evt);\n\n } else {\n evt = $close[b]['id'];\n } \n\n\n if ( typeof(gina.events[evt]) == 'undefined' || gina.events[evt] != $close[b].id ) {\n register('close', evt, $close[b])\n }\n }\n \n // link events\n i = 0; len = $link.length;\n var _form = null, f = null, fLen = null;\n var inheritedData = {}, _formData = null;\n var domParserObject = new DOMParser()\n , currentId = null\n , found = null\n , aHref = null\n , isSubmitLink = null\n , isLink = null\n ;\n \n for (; i < len; ++i) {\n // if is disabled, stop propagation\n if ( $link[i].getAttribute('disabled') != null ) {\n continue;\n }\n \n $link[i]['id'] = ( /^null$/i.test($link[i].getAttribute('id')) ) ? null : $link[i].getAttribute('id'); \n if (!$link[i]['id'] || !/^popin\\.link/.test($link[i]['id']) || !/^popin\\.click/.test($link[i]['id']) ) {\n \n // just in case\n isLink = true;\n aHref = $link[i].getAttribute('href');\n if (!aHref || aHref == '' || aHref == '#' ) {\n if (aHref != '#')\n $link[i].setAttribute('href', '#');\n isLink = false;\n }\n // link or action ? \n if (/^null$/i.test($link[i]['id'])) {\n if ( isLink ) {\n evt = 'popin.link.' + uuid.v4();\n $link[i].setAttribute('data-gina-popin-is-link', true);\n } else {\n evt = 'popin.click.' + uuid.v4();\n $link[i].setAttribute('data-gina-popin-is-link', false);\n }\n } else {\n evt = $link[i]['id'];\n }\n \n $link[i]['id'] = evt; \n $link[i].setAttribute( 'id', evt);\n \n } else {\n evt = $link[i]['id'];\n }\n \n // ignore `isSubmitLink == true`\n // will be handled by validator\n isSubmitLink = $link[i].getAttribute('data-gina-form-submit');\n isSubmitLink = ( isSubmitLink && /^true$/i.test(isSubmitLink) ) ? true : false; \n if (isSubmitLink) {\n continue;\n }\n \n \n if ( !/^(null|\\s*)$/.test($link[i].getAttribute('href')) ) {\n addListener(gina, $link[i], 'click', function(linkEvent) {\n linkEvent.preventDefault();\n \n $popin.isRedirecting = true;\n \n if ($popin.hasForm) {\n // Experimental - inheritedData\n // Inhertitance from previously request: merging datas with current form context\n // TODO - Get the inhereted data from LMDB Database using the form CSRF\n _form = $popin.target.getElementsByTagName('FORM');\n f = 0; fLen = _form.length;\n for (; f < fLen; ++f) {\n // check if current link is in form\n currentId = linkEvent.currentTarget.id;\n found = domParserObject.parseFromString(_form.item(f).innerHTML, 'text/html').getElementById(currentId) || false;\n if ( found ) {\n _formData = _form[f].getAttribute('data-gina-form-inherits-data') || null;\n // mergin GET data\n inheritedData = merge(inheritedData, JSON.parse(decodeURIComponent(_formData)));\n }\n }\n \n // has already params ?\n if ( inheritedData.count() > 0 ) {\n if ( /\\?/.test(linkEvent.currentTarget.href) ) {\n linkEvent.currentTarget.href += '&inheritedData=' + encodeURIComponent(JSON.stringify(inheritedData));\n } else {\n linkEvent.currentTarget.href += '?inheritedData=' + encodeURIComponent(JSON.stringify(inheritedData));\n }\n } \n }\n })\n }\n\n if ( typeof(gina.events[evt]) == 'undefined' || gina.events[evt] != $link[i].id ) {\n register('link', evt, $link[i])\n }\n \n \n } // EO for(; i < len; ++i) \n \n // bind with formValidator if forms are found\n if ($popin.hasForm) {\n var _id = null;\n var $forms = $el.getElementsByTagName('form');\n i = 0; len = $forms.length;\n for(; i < len; ++i) {\n\n if ( !$forms[i]['id'] || typeof($forms[i]) != 'string' ) {\n _id = $forms[i].getAttribute('id') || 'form.' + uuid.v4();\n $forms[i].setAttribute('id', _id);// just in case\n $forms[i]['id'] = _id\n } else {\n _id = $forms[i]['id']\n }\n\n //console.debug('pushing ', _id, $forms[i]['id'], typeof($forms[i]['id']), $forms[i].getAttribute('id'));\n if ($popin['$forms'].indexOf(_id) < 0)\n $popin['$forms'].push(_id);\n\n $forms[i].close = popinClose;\n $validatorInstance.isPopinContext = true;\n $validatorInstance.validateFormById($forms[i].getAttribute('id')); //$forms[i]['id']\n\n removeListener(gina, $popin.target, eventType);\n }\n }\n \n }\n \n function updateToolbar(result, resultIsObject) {\n // update toolbar errors\n var $popin = getActivePopin();\n \n if ( gina && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar && typeof(result) != 'undefined' && typeof(resultIsObject) != 'undefined' && result ) {\n \n var XHRData = result;\n \n try { \n var XHRDataNew = null;\n if ( !resultIsObject && XHRData.error && /^(\\{|\\[)/.test(XHRData.error) )\n XHRData.error = JSON.parse(XHRData.error);\n \n // bad .. should not happen\n if ( typeof(XHRData.error) != 'undefined' && typeof(XHRData.error) == 'object' && typeof(XHRData.error) == 'object' ) {\n // by default\n XHRDataNew = { 'status' : XHRData.status };\n // existing will be overriden by user\n for (xErr in XHRData.error) {\n if ( !/^error$/.test(xErr ) ) {\n XHRDataNew[xErr] = XHRData.error[xErr];\n }\n }\n\n XHRDataNew.error = XHRData.error.error;\n\n XHRData = result = XHRDataNew\n } else if ( typeof(XHRData.error) != 'undefined' && typeof(XHRData.error) == 'string' ) {\n XHRData = result;\n }\n \n XHRData.isXHRViewData = true;\n ginaToolbar.update('data-xhr', XHRData );\n return;\n } catch (err) {\n throw err\n }\n }\n \n // update toolbar\n try {\n var $popin = getPopinById(instance.activePopinId);\n var $el = $popin.target;\n } catch (err) {\n ginaToolbar.update('data-xhr', err );\n }\n \n \n // XHRData\n var XHRData = null; \n if ( typeof(result) == 'string' && /\\<(.*)\\>/.test(result) ) {\n // converting Element to DOM object\n XHRData = new DOMParser().parseFromString(result, 'text/html').getElementById('gina-without-layout-xhr-data'); \n } else {\n XHRData = document.getElementById('gina-without-layout-xhr-data');\n }\n \n if ( gina && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar && XHRData ) {\n try {\n\n if ( typeof(XHRData.value) != 'undefined' && XHRData.value ) {\n XHRData = JSON.parse( decodeURIComponent( XHRData.value ) );\n // reset data-xhr\n XHRData.isXHRViewData = true;\n ginaToolbar.update('data-xhr', XHRData);\n }\n\n } catch (err) {\n throw err\n }\n }\n\n // XHRView\n var XHRView = null;\n if ( typeof(result) == 'string' && /\\<(.*)\\>/.test(result) ) { \n // converting Element to DOM object\n XHRView = new DOMParser().parseFromString(result, 'text/html').getElementById('gina-without-layout-xhr-view'); \n } else {\n XHRView = document.getElementById('gina-without-layout-xhr-view');\n }\n \n if ( gina && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar && XHRView ) {\n try {\n\n if ( typeof(XHRView.value) != 'undefined' && XHRView.value ) {\n \n XHRView = JSON.parse( decodeURIComponent( XHRView.value ) ); \n // reset data-xhr\n //ginaToolbar.update(\"view-xhr\", null);\n ginaToolbar.update('view-xhr', XHRView);\n }\n\n // popin content\n ginaToolbar.update('el-xhr', $popin.id);\n\n } catch (err) {\n throw err\n }\n }\n }\n\n\n\n /**\n * XML Request options\n * */\n var xhrOptions = {\n 'url' : '',\n 'method' : 'GET',\n 'isSynchrone' : false,\n 'withCredentials': true, // if should be enabled under a trusted env\n 'headers' : {\n // cross domain is enabled by default, but you need to setup `Access-Control-Allow-Origin`\n 'X-Requested-With': 'XMLHttpRequest' // to set isXMLRequest == true && in case of cross domain origin\n\n }\n };\n\n /**\n * popinLoad\n *\n * @param {string} name\n * @param {string} url\n * @param {object} [options]\n * */\n function popinLoad(name, url, options) {\n // if no name defiend, get the current\n if ( typeof(name) == 'undefined' ) {\n if ( typeof(this.name) == 'undefined' ) {\n throw new Error('`$popin.name` needs to be defined !')\n }\n name = this.name;\n } else if (typeof(this.name) == 'undefined' && name != 'undefined') {\n this.name = name;\n }\n // popin object\n var $popin = getPopinByName(name);\n var id = $popin.id;\n \n // set as active if none is active\n if ( !gina.popin.activePopinId ) {\n gina.popin.activePopinId = id;\n }\n \n // popin element\n var $el = document.getElementById(id) || null;\n\n if ( $el == null ) {\n\n var className = $popin.options.class +' '+ id;\n $el = document.createElement('div');\n $el.setAttribute('id', id);\n $el.setAttribute('class', className);\n instance.target.firstChild.appendChild($el);\n }\n\n if ( typeof(options) == 'undefined' ) {\n options = xhrOptions;\n } else {\n // In order to inherit without overriding default xhrOptions\n var isWithCredentials = xhrOptions.withCredentials;\n options = merge(options, xhrOptions);\n \n options.withCredentials = isWithCredentials;\n }\n \n if ( \n /^(http|https)\\:/.test(url)\n && !new RegExp('^' + window.location.protocol + '//'+ window.location.host).test(url) \n ) {\n // is request from same domain ?\n //options.headers['Origin'] = window.protocol+'//'+window.location.host;\n //options.headers['Origin'] = '*';\n //options.headers['Host'] = 'https://domain.local:3154';\n var isSameDomain = ( new RegExp(window.location.hostname).test(url) ) ? true : false;\n if (!isSameDomain) {\n // proxy external urls\n // TODO - instead of using `cors.io` or similar services, try to intégrate a local CORS proxy similar to : http://oskarhane.com/avoid-cors-with-nginx-proxy_pass/\n //url = url.match(/^(https|http)\\:/)[0] + '//cors.io/?' + url;\n url = url.match(/^(https|http)\\:/)[0] + '//corsacme.herokuapp.com/?'+ url;\n //url = url.match(/^(https|http)\\:/)[0] + '//cors-anywhere.herokuapp.com/' + url;\n \n //delete options.headers['X-Requested-With']\n \n // remove credentials on untrusted env\n // if forced by user options, it will be restored with $popin.options merge\n options.withCredentials = false;\n }\n }\n options.url = url;\n // updating popin options\n $popin.options = merge(options, $popin.options);\n\n\n if ( options.withCredentials ) { // Preflighted requests \n if ('withCredentials' in xhr) {\n // XHR for Chrome/Firefox/Opera/Safari.\n if (options.isSynchrone) {\n xhr.open(options.method, options.url, options.isSynchrone)\n } else {\n xhr.open(options.method, options.url)\n }\n } else if ( typeof XDomainRequest != 'undefined' ) {\n // XDomainRequest for IE.\n xhr = new XDomainRequest();\n xhr.open(options.method, options.url);\n } else {\n // CORS not supported.\n xhr = null;\n var result = 'CORS not supported: the server is missing the header `\"Access-Control-Allow-Credentials\": true` ';\n triggerEvent(gina, $el, 'error.' + id, result)\n }\n } else { // simple requests\n \n if (options.isSynchrone) {\n xhr.open(options.method, options.url, options.isSynchrone)\n } else {\n xhr.open(options.method, options.url)\n }\n }\n\n \n\n if (xhr) {\n // setting up headers\n xhr.withCredentials = ( typeof(options.withCredentials) != 'undefined' ) ? options.withCredentials : false;\n \n xhr.onerror = function(event, err) {\n \n var error = 'Transaction error: might be due to the server CORS settings.\\nPlease, check the console for more details.';\n var result = {\n 'status': xhr.status, //500,\n 'error' : error\n }; \n \n var resultIsObject = true;\n instance.eventData.error = result +'/n'+ err; \n updateToolbar(result, resultIsObject);\n triggerEvent(gina, $el, 'error.' + id, result)\n }\n \n \n for (var header in options.headers) {\n xhr.setRequestHeader(header, options.headers[header]);\n }\n \n \n // catching ready state cb\n xhr.onreadystatechange = function (event) {\n if (xhr.readyState == 4) {\n // 200, 201, 201' etc ...\n if( /^2/.test(xhr.status) ) {\n\n try {\n var result = xhr.responseText\n , contentType = xhr.getResponseHeader(\"Content-Type\")\n , isJsonContent = (/application\\/json/.test( contentType )) ? true : false\n , isRedirecting = true // by default\n ;\n if ( isJsonContent ) {\n result = JSON.parse(xhr.responseText);\n result.status = xhr.status;\n result.contentType = contentType;\n isRedirecting = false;\n }\n \n\n instance.eventData.success = result;\n \n if ( \n !isJsonContent && $popin.isOpen && !$popin.hasForm\n ||\n !isJsonContent && $popin.isOpen && isRedirecting\n ) { \n popinLoadContent(result, isRedirecting);\n } else {\n \n if ( \n isJsonContent && typeof(result.location) != 'undefined' \n ||\n isJsonContent && typeof(result.reload) != 'undefined'\n ) {\n var isXhrRedirect = false;\n if (\n typeof(result.isXhrRedirect) != 'undefined'\n && /^true$/i.test(result.isXhrRedirect)\n ) {\n isXhrRedirect = true;\n }\n if ( typeof(result.location) != 'undefined' && isXhrRedirect ) {\n \n if ( \n typeof(result.popin) != 'undefined' \n && typeof(result.popin.close) != 'undefined'\n ) {\n $popin.isRedirecting = false;\n $popin.close();\n \n var _reload = (result.popin.reload) ? result.popin.reload : false;\n if ( !result.popin.location && !result.popin.url) {\n delete result.popin;\n // only exception\n if (_reload) {\n result.popin = { reload: _reload };\n }\n } \n }\n \n var _target = '_self'; // by default\n if ( typeof(result.target) != 'undefined' ) {\n if ( /^(blank|self|parent|top)$/ ) {\n result.target = '_'+result.target;\n }\n _target = result.target\n }\n \n // special case of location without having the popin open\n // can occure while tunnelling\n if ( /^_self$/.test(_target) ) {\n var popinUrl = null;\n if ( typeof(result.popin) != 'undefined' ) {\n popinUrl = result.popin.location || result.popin.url;\n } else {\n popinUrl = result.location;\n }\n \n $popin\n .load( $popin.name, popinUrl, $popin.options );\n return setTimeout( function onPopinredirect($popin){\n if (!$popin.isOpen) {\n $popin.open();\n return;\n }\n }, 50, $popin);\n }\n \n \n window.open(result.location, _target);\n return;\n }\n \n if ( typeof(result.location) != 'undefined' ) {\n document.location = result.location;\n return;\n }\n \n if ( typeof(result.reload) != 'undefined' ) {\n document.location.reload();\n return;\n }\n \n if ( typeof(result.popin) != 'undefined' ) {\n if ( typeof(result.popin.close) != 'undefined' ) {\n $popin.isRedirecting = false;\n popinClose($popin.name);\n }\n }\n }\n \n //if ( !isJsonContent && $popin.hasForm) {\n //$validatorInstance.handleXhrResponse(xhr, $forms[0], $forms[0].id, event, true);\n //handleXhr(xhr, $el, options, require)\n //return\n //}\n if ( !isJsonContent ) {\n triggerEvent(gina, $el, 'loaded.' + id, result);\n return\n }\n \n triggerEvent(gina, $forms[0], 'success.' + id, result);\n \n }\n \n if (GINA_ENV_IS_DEV)\n updateToolbar(result);\n\n } catch (err) {\n \n var resultIsObject = false;\n \n var result = {\n 'status': 422,\n 'error' : err.description || err.stack\n };\n \n if ( /application\\/json/.test( xhr.getResponseHeader(\"Content-Type\") ) ) {\n result.error = JSON.parse(xhr.responseText);\n resultIsObject = true\n }\n\n instance.eventData.error = result;\n if (GINA_ENV_IS_DEV)\n updateToolbar(result, resultIsObject);\n\n triggerEvent(gina, $el, 'error.' + id, result)\n }\n\n } else {\n //console.log('error event triggered ', event.target, $form);\n var resultIsObject = false;\n var result = {\n 'status': xhr.status,\n 'error' : xhr.responseText\n };\n\n if ( /application\\/json/.test( xhr.getResponseHeader(\"Content-Type\") ) ) {\n result.error = JSON.parse(xhr.responseText);\n resultIsObject = true\n }\n\n instance.eventData.error = result; \n \n\n // update toolbar\n if (GINA_ENV_IS_DEV)\n updateToolbar(result, resultIsObject);\n\n triggerEvent(gina, $el, 'error.' + id, result)\n }\n }\n };\n\n // catching request progress\n // xhr.onprogress = function(event) {\n // //console.log(\n // // 'progress position '+ event.position,\n // // '\\nprogress total size '+ event.totalSize\n // //);\n //\n // var percentComplete = (event.position / event.totalSize)*100;\n // var result = {\n // 'status': 100,\n // 'progress': percentComplete\n // };\n //\n // instance.eventData.onprogress = result;\n //\n // triggerEvent(gina, $el, 'progress.' + id, result)\n // };\n\n // catching timeout\n // xhr.ontimeout = function (event) {\n // var result = {\n // 'status': 408,\n // 'error': 'Request Timeout'\n // };\n //\n // instance.eventData.ontimeout = result;\n //\n // triggerEvent(gina, $el, 'error.' + id, result)\n // };\n\n\n // sending\n //var data = JSON.stringify({ sample: 'data'});\n xhr.send();\n \n\n return {\n 'open': function () {\n var fired = false;\n addListener(gina, $el, 'loaded.' + id, function(e) {\n \n e.preventDefault();\n\n if (!fired) {\n fired = true;\n \n instance.activePopinId = $popin.id;\n popinBind(e, $popin);\n popinOpen($popin.name);\n }\n });\n\n }\n }\n }\n\n }\n\n /**\n * popinLoadContent\n * \n * @param {string} html - plain/text\n * @param {boolean} [isRedirecting] - to handle link inside popin without form\n */\n function popinLoadContent(stringContent, isRedirecting) {\n \n var $popin = getActivePopin(); \n if ( !$popin ) { \n return;\n }\n if (!$popin.isOpen)\n throw new Error('Popin `'+$popin.name+'` is not open !');\n \n $popin.isRedirecting = ( typeof(isRedirecting) != 'undefined' ) ? isRedirecting : false;\n \n var $el = $popin.target;\n // if ( \n // typeof(stringContent) != 'undefined' \n // && typeof(stringContent.trim) == 'function' \n // ) {\n $el.innerHTML = stringContent.trim(); \n // }\n \n popinUnbind($popin.name, true); \n popinBind({ target: $el, type: 'loaded.' + $popin.id }, $popin);\n \n if ( !$popin.isRedirecting ) {\n triggerEvent(gina, instance.target, 'open.'+ $popin.id, $popin);\n } else {\n triggerEvent(gina, instance.target, 'loaded.' + $popin.id, $popin);\n }\n }\n \n function getScript(source) { \n // then trigger scripts load\n //var xhr = new XMLHttpRequest();\n var xhr = setupXhr();\n xhr.open('GET', source, true);\n xhr.setRequestHeader(\"Content-Type\", \"text/javascript\");\n xhr.onload = function () {\n eval(xhr.response);\n };\n xhr.send(); \n }\n \n /**\n * popinOpen\n * \n * If you get a x-origin error, check if you have `Vary` rule\n * set in your policy : // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary\n * \n * Add to your project/env.json the following rule\n * { \n * \"$bundle\" : {\n * \"server\": {\n * \"response\": {\n * // other definitions ...\n * \n * \"vary\": \"Origin\"\n * }\n * }\n * } \n * }\n * \n * Opens a popin by name\n *\n * @parama {string} name\n *\n * */\n function popinOpen(name) {\n\n var id = null, $el = null;\n var $popin = ( typeof(name) != 'undefined') ? getPopinByName(name) : getPopinById(this.id);\n if ( !$popin ) {\n throw new Error('Popin name `'+name+'` not found !')\n } \n id = $popin.id;\n $el = document.getElementById(id);\n \n // load external ressources in order of declaration\n // TODO - Add support for stylesheets\n var globalScriptsList = $popin.parentScripts\n , scripts = $el.getElementsByTagName('script')\n //, globalStylesList = $popin.parentStyles\n , i = 0\n , len = scripts.length\n ;\n var domain = gina.config.hostname.replace(/(https|http|)\\:\\/\\//, '').replace(/\\:\\d+$/, '');\n var reDomain = new RegExp(domain+'\\:\\\\d+\\|'+domain); \n for (;i < len; ++i) {\n if ( typeof(scripts[i].src) == 'undefined' || scripts[i].src == '' ) {\n continue;\n }\n let filename = scripts[i].src\n .replace(/(https|http|)\\:\\/\\//, '')\n .replace(reDomain, '');\n // don't load if already in the global context\n if ( globalScriptsList.indexOf(filename) > -1 )\n continue;\n \n getScript(scripts[i].src);\n }\n //i = 0; len = styles.length\n \n popinBind({ target: $el, type: 'loaded.' + $popin.id }, $popin);\n \n\n if ( !/gina-popin-is-active/.test($el.className) )\n $el.className += ' gina-popin-is-active';\n\n // overlay\n if ( !/gina-popin-is-active/.test(instance.target.firstChild.className) )\n instance.target.firstChild.className += ' gina-popin-is-active'; \n // overlay\n if ( /gina-popin-is-active/.test(instance.target.firstChild.className) ) {\n removeListener(gina, instance.target, 'open.'+ $popin.id)\n }\n\n $popin.isOpen = true;\n // so it can be forwarded to the handler who is listening\n $popin.target = $el;\n \n instance.activePopinId = $popin.id;\n\n // update toolbar\n if (GINA_ENV_IS_DEV)\n updateToolbar();\n // var XHRData = document.getElementById('gina-without-layout-xhr-data');\n // if ( gina && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar && XHRData ) {\n // try {\n\n // if ( typeof(XHRData.value) != 'undefined' && XHRData.value ) {\n // XHRData = JSON.parse( decodeURIComponent( XHRData.value ) );\n // // reset data-xhr\n // ginaToolbar.update(\"data-xhr\", null);\n // XHRData.isXHRViewData = true;\n // ginaToolbar.update(\"data-xhr\", XHRData);\n // }\n\n // } catch (err) {\n // throw err\n // }\n // }\n\n // var XHRView = document.getElementById('gina-without-layout-xhr-view');\n // if ( gina && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar && XHRView ) {\n // try {\n\n // if ( typeof(XHRView.value) != 'undefined' && XHRView.value ) {\n // XHRView = JSON.parse( decodeURIComponent( XHRView.value ) );\n // // reset data-xhr\n // ginaToolbar.update(\"view-xhr\", null);\n\n // ginaToolbar.update(\"view-xhr\", XHRView);\n // }\n\n // // popin content\n // ginaToolbar.update(\"el-xhr\", id);\n\n // } catch (err) {\n // throw err\n // }\n // }\n\n triggerEvent(gina, instance.target, 'open.'+ $popin.id, $popin);\n }\n\n /**\n * popinUnbind\n *\n * Closes a popin by `name` or all `is-active`\n *\n * @parama {string} [name]\n *\n * */\n function popinUnbind(name, isRouting) {\n \n var $popin = ( typeof(name) != 'undefined') ? getPopinByName(name) : getActivePopin();\n var $el = null;\n if ( !$popin && typeof(name) != 'undefined' ) {\n throw new Error('Popin `'+name+'` not found !');\n }\n \n // by default\n if ( typeof($popin) != 'undefined' && $popin != null ) {\n $el = $popin.target;\n \n isRouting = ( typeof(isRouting) != 'undefined' ) ? isRouting : false;\n\n if ( $el != null && /gina-popin-is-active/.test($el.className) ) {\n if (!isRouting) {\n instance.target.firstChild.className = instance.target.firstChild.className.replace(/\\sgina-popin-is-active|gina-popin-is-active|gina-popin-is-active\\s/, '');\n $el.className = $el.className.replace(/\\sgina-popin-is-active|gina-popin-is-active|gina-popin-is-active\\s/, '');\n $el.innerHTML = '';\n } \n\n // removing from FormValidator instance\n if ($validatorInstance) {\n var i = 0, formsLength = $popin['$forms'].length;\n if ($validatorInstance['$forms'] && formsLength > 0) {\n for (; i < formsLength; ++i) {\n if ( typeof($validatorInstance['$forms'][ $popin['$forms'][i] ]) != 'undefined' )\n $validatorInstance['$forms'][ $popin['$forms'][i] ].destroy();\n\n $popin['$forms'].splice( i, 1);\n }\n }\n }\n \n gina.popinIsBinded = false;\n \n // remove listeners\n removeListener(gina, $popin.target, 'loaded.' + $popin.id);\n }\n } \n }\n \n\n /**\n * popinClose\n *\n * Closes a popin by `name` or all `is-active`\n *\n * @parama {string} [name]\n *\n * */\n function popinClose(name) {\n \n var $popin = null;\n if ( typeof(name) == 'undefined' && /^true$/.test(this.isOpen) ) {\n name = this.name;\n $popin = this;\n } else {\n $popin = getPopinByName(name) || getActivePopin();\n if (!$popin)\n return;\n \n name = $popin.name;\n }\n //var $popin = ( typeof(name) != 'undefined') ? getPopinByName(name) : getActivePopin();\n var $el = null;\n if ( !$popin && typeof(name) != 'undefined' ) {\n throw new Error('Popin `'+name+'` not found !');\n }\n if (!$popin.isOpen)\n return;\n \n // by default\n if ( typeof($popin) != 'undefined' && $popin != null ) {\n \n // in case popinClose is called by the user e.g.: binding cancel/close with a <A> tag\n // but at the same time, the <A> href is not empty -> redirection wanted in the HTML\n // in this case, we want to ignore close\n if ( $popin.isRedirecting )\n return;\n \n $el = $popin.target;\n \n removeListener(gina, $popin.target, 'ready.' + instance.id);\n \n if ( $popin.hasForm ) {\n $popin.hasForm = false;\n }\n\n if ( $el != null && /gina-popin-is-active/.test($el.className) ) {\n \n popinUnbind(name); \n $popin.isOpen = false;\n gina.popinIsBinded = false; \n\n // restore toolbar\n if ( GINA_ENV_IS_DEV && gina && typeof(window.ginaToolbar) != 'undefined' && window.ginaToolbar )\n ginaToolbar.restore();\n\n instance.activePopinId = null;\n if ( $popin.$headers.length > 0) {\n var s = 0\n , sLen = $popin.$headers.length\n ;\n try {\n for (; s<sLen; ++s) {\n document.getElementById( $popin.$headers[s].id ).remove(); \n }\n } catch(err){\n console.warn('Could not remove script `'+ $popin.$headers[s].id +'`\\n'+ err.stack)\n }\n $popin.$headers = []; \n }\n triggerEvent(gina, $popin.target, 'close.'+ $popin.id, $popin);\n }\n } \n }\n\n /**\n * popinDestroy\n *\n * Destroyes a popin by name\n *\n * @parama {string} name\n *\n * */\n function popinDestroy(name) {\n \n var $popin = ( typeof(name) != 'undefined') ? getPopinByName(name) : getActivePopin();\n var id = null, $el = null;\n if ( !$popin && typeof(name) != 'undefined' ) {\n throw new Error('Popin `'+name+'` not found !');\n }\n \n id = $popin.id;\n }\n \n function registerPopin($popin, options) {\n \n if ( typeof(options) != 'object' ) {\n throw new Error('`options` must be an object')\n }\n \n $popin.options = merge(options, self.options);\n $popin.id = 'gina-popin-' + instance.id +'-'+ $popin.options['name'];\n \n if ( typeof(instance.$popins[$popin.id]) == 'undefined' ) { \n\n if ( typeof($popin.options['name']) != 'string' || $popin.options['name'] == '' ) {\n throw new Error('`options.name` can not be left `empty` or `undefined`')\n }\n\n if ( registeredPopins.indexOf($popin.options['name']) > -1 ) {\n throw new Error('`popin '+$popin.options['name']+'` already exists !')\n }\n\n // import over plugins\n if ( typeof($popin.options['validator']) != 'undefined' ) {\n $validatorInstance = $popin.options['validator'];\n $popin.validateFormById = $validatorInstance.validateFormById;\n }\n \n\n $popin.options['class'] = 'gina-popin-container ' + $popin.options['class'];\n\n \n $popin.name = $popin.options['name']; \n $popin.target = instance.target; \n $popin.load = popinLoad;\n $popin.loadContent = popinLoadContent;\n $popin.open = popinOpen;\n $popin.close = popinClose;\n if (GINA_ENV_IS_DEV)\n $popin.updateToolbar = updateToolbar;\n \n // Get main ressources\n $popin.parentScripts = [];\n $popin.parentStyles = [];\n var domain = gina.config.hostname.replace(/(https|http|)\\:\\/\\//, '').replace(/\\:\\d+$/, '');\n var reDomain = new RegExp(domain+'\\:\\\\d+\\|'+domain);\n // Parent scripts\n var mainDocumentScripts = document.getElementsByTagName('script');\n for (let s = 0, len = mainDocumentScripts.length; s < len; s++ ) {\n if (!mainDocumentScripts[s].src || mainDocumentScripts[s].src == '')\n continue;\n // Filename without domain\n let filename = mainDocumentScripts[s].src\n .replace(/(https|http|)\\:\\/\\//, '')\n .replace(reDomain, '');\n $popin.parentScripts[s] = filename;\n }\n // Parent Styles\n var mainDocumentStyles = document.getElementsByTagName('link'); \n for (let s = 0, len = mainDocumentStyles.length; s < len; s++ ) {\n if ( typeof(mainDocumentStyles[s].rel) == 'undefined' || !/stylesheet/i.test(mainDocumentStyles[s].rel) )\n continue;\n // Filename without domain\n let filename = mainDocumentStyles[s].href\n .replace(/(https|http|)\\:\\/\\//, '')\n .replace(reDomain, '');\n $popin.parentStyles[s] = filename;\n }\n \n \n \n instance.$popins[$popin.id] = $popin;\n\n // setting up AJAX\n if (window.XMLHttpRequest) { // Mozilla, Safari, ...\n xhr = new XMLHttpRequest();\n } else if (window.ActiveXObject) { // IE\n try {\n xhr = new ActiveXObject(\"Msxml2.XMLHTTP\");\n } catch (e) {\n try {\n xhr = new ActiveXObject(\"Microsoft.XMLHTTP\");\n }\n catch (e) {}\n }\n }\n \n \n \n bindOpen($popin); \n }\n }\n\n var init = function(options) {\n \n setupInstanceProto();\n //instance.on('init', function(event) {\n addListener(gina, instance.target, 'init.'+instance.id, function(e) {\n \n var $newPopin = null;\n var popinId = 'gina-popin-' + instance.id +'-'+ options['name'];\n if ( typeof(instance.$popins[popinId]) == 'undefined' ) { \n var $newPopin = merge({}, $popin); \n registerPopin($newPopin, options);\n }\n\n instance.isReady = true;\n gina.hasPopinHandler = true;\n gina.popin = merge(gina.popin, instance);\n // trigger popin ready event\n triggerEvent(gina, instance.target, 'ready.' + instance.id, $newPopin);\n });\n\n \n \n\n instance.initialized = true;\n\n return instance\n }\n \n var setupInstanceProto = function() {\n instance.getPopinById = getPopinById;\n instance.getPopinByName = getPopinByName;\n instance.load = popinLoad;\n instance.loadContent = popinLoadContent;\n instance.getActivePopin = getActivePopin;\n instance.open = popinOpen;\n instance.close = popinClose;\n }\n \n\n if ( !gina.hasPopinHandler ) {\n popinCreateContainer();\n } else {\n popinGetContainer()\n }\n\n return init(options)\n };\n\n return Popin\n});\n",
51
51
  "/**\n * Operations on element\n * - animations\n * */\nfunction fadeIn(element) {\n var op = 0.1; // initial opacity\n element.style.display = 'block';\n var timer = setInterval(function () {\n if (op >= 1){\n clearInterval(timer);\n }\n element.style.opacity = op;\n element.style.filter = 'alpha(opacity=' + op * 100 + \")\";\n op += op * 0.1;\n }, 10);\n}\n\nfunction fadeOut(element) {\n var op = 1; // initial opacity\n var timer = setInterval(function () {\n if (op <= 0.1){\n clearInterval(timer);\n element.style.display = 'none';\n }\n element.style.opacity = op;\n element.style.filter = 'alpha(opacity=' + op * 100 + \")\";\n op -= op * 0.1;\n }, 50);\n}\n;\ndefine(\"utils/effects\", function(){});\n\n",
52
52
  "/**\n * Object.assign\n * Ref.: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\n * \n */\nif (typeof Object.assign !== 'function') {\n // Must be writable: true, enumerable: false, configurable: true\n Object.defineProperty(Object, \"assign\", {\n value: function assign(target, varArgs) { // .length of function is 2\n 'use strict';\n if (target === null || target === undefined) {\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n var to = Object(target);\n for (var index = 1; index < arguments.length; index++) {\n var nextSource = arguments[index];\n\n if (nextSource !== null && nextSource !== undefined) {\n for (var nextKey in nextSource) {\n // Avoid bugs when hasOwnProperty is shadowed\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n },\n writable: true,\n configurable: true\n });\n}\n \nif ( typeof(JSON.clone) == 'undefined' ) {\n /**\n * JSON.clone\n * Clone JSON object\n * \n * Changes made here must be reflected in: \n * - gina/utils/prototypes.js\n * - gina/framework/version/helpers/prototypes.js\n * - gina/framework/version/core/asset/js/plugin/src/gina/utils/polyfill.js\n * \n * @param {object} source\n * @param {object} [target]\n * \n * @return {object} cloned JSON object\n **/\n var clone = function(source, target) {\n if (source == null || typeof source != 'object') return source;\n if (source.constructor != Object && source.constructor != Array) return source;\n if (source.constructor == Date || source.constructor == RegExp || source.constructor == Function ||\n source.constructor == String || source.constructor == Number || source.constructor == Boolean)\n return new source.constructor(source);\n\n target = target || new source.constructor();\n var i = 0\n , len = Object.getOwnPropertyNames(source).length || 0\n , keys = Object.keys(source)\n ;\n \n while (i<len) {\n target[keys[i]] = (typeof target[keys[i]] == 'undefined') ? clone(source[keys[i]], null) : target[keys[i]];\n i++;\n }\n i = null; len = null; keys = null;\n\n return target;\n };\n \n JSON.clone = clone;\n // WHY NOT USE SOMETHING ELSE ?\n // Could have been fine, but not working when you have references pointg to another object\n // return Object.assign({}, source); \n \n // Performences issue\n //return JSON.parse(JSON.stringify(source));\n}\n\nif ( typeof(JSON.escape) == 'undefined' ) {\n /**\n * JSON.escape\n * Escape special characters\n * \n * Changes made here must be reflected in: \n * - gina/utils/prototypes.js\n * - gina/framework/version/helpers/prototypes.js\n * - gina/framework/version/core/asset/js/plugin/src/gina/utils/polyfill.js\n * \n * @param {object} jsonStr\n * \n * @return {object} escaped JSON string\n **/\n var escape = function(jsonStr){\n try {\n return jsonStr\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\t/g, \"\\\\t\")\n ;\n } catch (err) { \n throw err;\n }\n };\n \n JSON.escape = escape;\n};\ndefine(\"utils/polyfill\", function(){});\n\n",
53
- "'use strict';\n/**\n * This file is part of the gina package.\n * Copyright (c) 2009-2022 Rhinostone <contact@gina.io>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * @class Inherits\n *\n * @package gina.utils\n * @namesame gina.utils.inherits\n * @author Rhinostone <contact@gina.io>\n *\n * @api Public\n * */\nfunction Inherits(a, b) {\n\n /**\n * init\n * @constructor\n * */\n var init = function(a, b) {\n var err = check(a, b);\n\n if (!err) {\n\n var z = (function() {\n var _inherited = false, cache = a;\n\n if (!_inherited) {\n _inherited = true;\n\n return function() {\n\n if (this) {\n this.prototype = cache.prototype;\n\n if (!this.name) this.name = cache.name;\n\n this.prototype.name = this.name;\n\n //makes it compatible with node.js classes like EventEmitter\n for (var prop in b.prototype) {\n if (!this[prop]) {\n this[prop] = b.prototype[prop];\n }\n }\n\n b.apply(this, arguments);\n cache.apply(this, arguments);\n }\n };\n }\n\n }(a, b));\n\n //makes it compatible with node.js classes like EventEmitter\n if (a.prototype == undefined) {\n a.prototype = {};\n }\n\n if (b.prototype == undefined) {\n b.prototype = {};\n }\n\n a.prototype = Object.create(b.prototype, {});\n z.prototype = Object.create(a.prototype, {}); //{ name: { writable: true, configurable: true, value: name }\n\n return z;\n } else {\n throw new Error(err);\n }\n };\n\n var check = function(a, b) {\n if ( typeof(a) == 'undefined' || typeof(b) == 'undefined') {\n return 'inherits(a, b): neither [ a ] nor [ b ] can\\'t be undefined or null'\n }\n return false;\n };\n\n return init;\n}\n\n\nif ( ( typeof(module) !== 'undefined' ) && module.exports ) {\n // Publish as node.js module\n module.exports = Inherits();\n} else if ( typeof(define) === 'function' && define.amd) {\n // Publish as AMD module\n define( 'utils/inherits',[],function() { return Inherits(); });\n};\n",
53
+ "'use strict';\n/**\n * This file is part of the gina package.\n * Copyright (c) 2009-2023 Rhinostone <contact@gina.io>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n/**\n * @class Inherits\n *\n * @package gina.utils\n * @namesame gina.utils.inherits\n * @author Rhinostone <contact@gina.io>\n *\n * @api Public\n * */\nfunction Inherits(a, b) {\n\n /**\n * init\n * @constructor\n * */\n var init = function(a, b) {\n var err = check(a, b);\n\n if (!err) {\n\n var z = (function() {\n var _inherited = false, cache = a;\n\n if (!_inherited) {\n _inherited = true;\n\n return function() {\n\n if (this) {\n this.prototype = cache.prototype;\n\n if (!this.name) this.name = cache.name;\n\n this.prototype.name = this.name;\n\n //makes it compatible with node.js classes like EventEmitter\n for (var prop in b.prototype) {\n if (!this[prop]) {\n this[prop] = b.prototype[prop];\n }\n }\n\n b.apply(this, arguments);\n cache.apply(this, arguments);\n }\n };\n }\n\n }(a, b));\n\n //makes it compatible with node.js classes like EventEmitter\n if (a.prototype == undefined) {\n a.prototype = {};\n }\n\n if (b.prototype == undefined) {\n b.prototype = {};\n }\n\n a.prototype = Object.create(b.prototype, {});\n z.prototype = Object.create(a.prototype, {}); //{ name: { writable: true, configurable: true, value: name }\n\n return z;\n } else {\n throw new Error(err);\n }\n };\n\n var check = function(a, b) {\n if ( typeof(a) == 'undefined' || typeof(b) == 'undefined') {\n return 'inherits(a, b): neither [ a ] nor [ b ] can\\'t be undefined or null'\n }\n return false;\n };\n\n return init;\n}\n\n\nif ( ( typeof(module) !== 'undefined' ) && module.exports ) {\n // Publish as node.js module\n module.exports = Inherits();\n} else if ( typeof(define) === 'function' && define.amd) {\n // Publish as AMD module\n define( 'utils/inherits',[],function() { return Inherits(); });\n};\n",
54
54
  "/**\n * Gina Frontend Framework\n *\n * Usage:\n * By adding gina tag in the end of the DOM ( just before </body>)\n *\n * <script type=\"text/javascript\" src=\"/js/vendor/gina/gina.min.js\"></script>\n *\n * You can add or edit config options through the `data-gina-config`\n * <script type=\"text/javascript\" src=\"/js/vendor/gina/gina.min.js\" data-gina-config=\"{ env: 'dev', envIsDev: true, webroot: '/' }\"></script>\n *\n * Through RequireJS\n *\n * var gina = require('gina');\n *\n * Useful Globals\n *\n * window['originalContext']\n * You have to passe your `jQuery` or your `DollarDom` context to Gina\n * e.g.: \n * window['originalContext'] = window['jQuery']\n * \n * This can be achieved by overriding `window['originalContext']` before defining your handler\n * Default value will be jQuery\n *\n * */\n\n//var wContext = ( typeof(window.onGinaLoaded) == 'undefined') ? window : parent.window; // iframe case\nvar readyList = [ { name: 'gina', ctx: window['gina'], fn: window.onGinaLoaded } ];\nvar readyFired = false;\nvar readyEventHandlersInstalled = false;\n\n// call this when the document is ready\n// this function protects itself against being called more than once\nfunction ready() {\n\n if (!readyFired) {\n // this must be set to true before we start calling callbacks\n readyFired = true;\n var result = null;\n var i = i || 0;\n\n var handleEvent = function (i, readyList) {\n\n if ( readyList[i] ) {\n\n if (readyList[i].name == 'gina') {\n\n var scheduler = window.setInterval(function (i, readyList) {\n try {\n if ( typeof(readyList) == 'undefined' ) {\n // Fixing init bug in chrome\n readyList = window.readyList;\n } \n readyList[i].ctx = window.gina;\n result = readyList[i].fn.call(window, readyList[i].ctx, window.require);\n\n // clear\n if (result) {\n window.clearInterval(scheduler);\n ++i;\n handleEvent(i, readyList);\n }\n } catch (err) {\n window.clearInterval(scheduler);\n throw err;\n }\n\n }, 50, i, readyList);\n\n\n } else { // onEachHandlerReady\n // iframe case\n if ( !window.$ && typeof(parent.window.$) != 'undefined' ) {\n window.$ = parent.window.$;\n }\n // by default, but can be overriden in your handler (before the handler definition)\n if ( typeof(window.originalContext) == 'undefined' && typeof(window.$) != 'undefined' ) {\n window.originalContext = window.$\n }\n readyList[i].ctx = window.originalContext || $;// passes the user's orignalContext by default; if no orignalContext is set will try users'jQuery\n readyList[i].fn.call(window, readyList[i].ctx, window.require);\n ++i;\n handleEvent(i, readyList);\n }\n\n } else { // end\n // allow any closures held by these functions to free\n readyList = [];\n }\n }\n\n handleEvent(i, readyList);\n }\n}\n\nfunction readyStateChange() {\n if ( document.readyState === 'complete' ) { \n gina.ready();\n }\n}\n\n\nif ( typeof(window['gina']) == 'undefined' ) {// could have be defined by loader\n\n var gina = {\n /**\n * ready\n * This is the one public interface use to wrap `handlers`\n * It is an equivalent of jQuery(document).ready(cb)\n *\n * No need to use it for `handlers`, it is automatically applied for each `handler`\n *\n * @callback {callback} callback\n * @param {object} [context] - if present, it will be passed\n * */\n /**@js_externs ready*/\n ready: function(callback, context) {\n\n\n // if ready has already fired, then just schedule the callback\n // to fire asynchronously, but right away\n if (readyFired) {\n setTimeout(function() {callback(context);}, 1);\n return;\n } else {\n // add the function and context to the list\n readyList.push({ name: 'anonymous', fn: callback, ctx: context });\n }\n\n // if document already ready to go, schedule the ready function to run\n // IE only safe when readyState is \"complete\", others safe when readyState is \"interactive\"\n if (document.readyState === \"complete\" || (!document.attachEvent && document.readyState === \"interactive\")) {\n setTimeout(ready, 1);\n } else if (!readyEventHandlersInstalled) {\n // otherwise if we don't have event handlers installed, install them\n if (document.addEventListener) {\n // first choice is DOMContentLoaded event\n document.addEventListener(\"DOMContentLoaded\", ready, false);\n // backup is window load event\n window.addEventListener(\"load\", ready, false);\n } else {\n // must be IE\n document.attachEvent(\"onreadystatechange\", readyStateChange);\n window.attachEvent(\"onload\", ready);\n }\n readyEventHandlersInstalled = true;\n }\n\n }\n };\n\n window['gina'] = gina;\n}\n\n\ndefine('core', ['require', 'gina'], function (require) {\n require('gina')(window['gina']); // passing core required lib through parameters\n});\n\n\nrequire.config({\n \"packages\": [\"gina\"]\n});\n\n// exporting\nrequire([\n //vendors\n \"vendor/uuid\",\n \"vendor/engine.io\",\n\n \"core\",\n // helpers\n \"helpers/prototypes\",\n \"helpers/binding\",\n \"helpers/dateFormat\",\n\n // plugins\n \"gina/link\",\n \"gina/validator\",\n \"gina/popin\",\n \"gina/storage\",\n\n // utils\n \"utils/dom\",\n \"utils/events\",\n \"utils/effects\",\n \"utils/polyfill\",\n \"utils/inherits\",\n //\"utils/merge\",\n \"utils/form-validator\",\n \"utils/collection\",\n \"utils/routing\"\n]);\n\n\n// catching freelancer script load event\nvar tags = document.getElementsByTagName('script');\n\nfor (var t = 0, len = tags.length; t < len; ++t) {\n\n if ( /gina.min.js|gina.js/.test( tags[t].getAttribute('src') ) ) {\n\n tags[t]['onload'] = function onGinaLoaded(e) {\n // TODO - get the version number from the response ?? console.log('tag ', tags[t].getAttribute('data-gina-config'));\n // var req = new XMLHttpRequest();\n // req.open('GET', document.location, false);\n // req.send(null);\n // var version = req.getAllResponseHeaders().match(/X-Powered-By:(.*)/)[0].replace('X-Powered-By: ', '');\n if (window['onGinaLoaded']) {\n var onGinaLoaded = window['onGinaLoaded']\n } else {\n function onGinaLoaded(gina) {\n\n if (!gina) {\n return false\n } else {\n if ( gina[\"isFrameworkLoaded\"] ) {\n return true\n }\n\n var options = gina['config'] = {\n /**@js_externs env*/\n //env : '{{ page.environment.env }}',\n /**@js_externs envIsDev*/\n envIsDev : ( /^true$/.test('{{ page.environment.envIsDev }}') ) ? true : false,\n /**@js_externs version*/\n //version : '{{ page.environment.version }}',\n /**@js_externs webroot*/\n 'webroot' : '{{ page.environment.webroot }}',\n };\n\n \n // globals\n window['GINA_ENV'] = '{{ GINA_ENV }}';\n window['GINA_ENV_IS_DEV'] = /true/i.test('{{ GINA_ENV_IS_DEV }}') ? true : false;\n if ( typeof(location.search) != 'undefined' && /debug\\=/i.test(window.location.search) ) {\n window['GINA_ENV_IS_DEV'] = gina['config']['envIsDev'] = options['envIsDev'] = /true/i.test(window.location.search.match(/debug=(true|false)/)[0].split(/\\=/)[1]) ? true: false; \n }\n\n gina[\"setOptions\"](options);\n gina[\"isFrameworkLoaded\"] = true;\n\n // making adding css to the head\n var link = null;\n link = document.createElement('link');\n link.href = options.webroot + \"css/vendor/gina/gina.min.css\";\n link.media = \"screen\";\n link.rel = \"stylesheet\";\n link.type = \"text/css\";\n document.getElementsByTagName('head')[0].appendChild(link);\n\n return true\n }\n }\n }\n\n\n if (document.addEventListener) {\n document.addEventListener(\"ginaloaded\", function(event){\n //console.log('Gina Framework is ready !');\n window['gina'] = event.detail;\n onGinaLoaded(event.detail)\n })\n } else if (document.attachEvent) {\n document.attachEvent(\"ginaloaded\", function(event){\n window['gina'] = event.detail;\n onGinaLoaded(event.detail)\n })\n }\n }()\n break;\n }\n};\n"
55
55
  ]
56
56
  }