spontaneous 0.1.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (556) hide show
  1. data/Gemfile +49 -0
  2. data/Gemfile.lock +146 -0
  3. data/LICENSE +0 -0
  4. data/README +0 -0
  5. data/Rakefile +284 -0
  6. data/Readme.markdown +7 -0
  7. data/application/css/add_alias_dialogue.scss +27 -0
  8. data/application/css/definitions.scss +249 -0
  9. data/application/css/developer.scss +9 -0
  10. data/application/css/editing.scss +649 -0
  11. data/application/css/login.scss +91 -0
  12. data/application/css/min/54ee0ed3c7fac7632bd5c020d69e9a2503e0c88c.css +1 -0
  13. data/application/css/min/c256adc144e2bdd0b0539356b04eb62db01e1dc3.css +1 -0
  14. data/application/css/popover.scss +335 -0
  15. data/application/css/schema_error.scss +90 -0
  16. data/application/css/spontaneous.scss +111 -0
  17. data/application/css/unsupported.scss +16 -0
  18. data/application/css/v2.scss +1606 -0
  19. data/application/css/variables.scss +80 -0
  20. data/application/js/add_alias_dialogue.js +59 -0
  21. data/application/js/add_home_dialogue.js +59 -0
  22. data/application/js/ajax.js +99 -0
  23. data/application/js/authentication.js +22 -0
  24. data/application/js/box.js +104 -0
  25. data/application/js/box_container.js +82 -0
  26. data/application/js/compatibility.js +132 -0
  27. data/application/js/conflicted_field_dialogue.js +92 -0
  28. data/application/js/content.js +224 -0
  29. data/application/js/content_area.js +44 -0
  30. data/application/js/dialogue.js +196 -0
  31. data/application/js/dom.js +71 -0
  32. data/application/js/edit_dialogue.js +137 -0
  33. data/application/js/edit_panel.js +232 -0
  34. data/application/js/editing.js +42 -0
  35. data/application/js/entry.js +13 -0
  36. data/application/js/extensions.js +104 -0
  37. data/application/js/field.js +4 -0
  38. data/application/js/field_preview.js +55 -0
  39. data/application/js/field_types/date_field.js +16 -0
  40. data/application/js/field_types/file_field.js +71 -0
  41. data/application/js/field_types/image_field.js +358 -0
  42. data/application/js/field_types/markdown_field.js +656 -0
  43. data/application/js/field_types/string_field.js +185 -0
  44. data/application/js/image.js +72 -0
  45. data/application/js/init.js +34 -0
  46. data/application/js/load.js +4 -0
  47. data/application/js/location.js +157 -0
  48. data/application/js/login.js +53 -0
  49. data/application/js/min/492a209de8ee955fa9c729a765377495001e11b1.js +17 -0
  50. data/application/js/min/80f684d77c940887a1d4a63e3a96102e993baa98.js +88 -0
  51. data/application/js/min/b8abf302a824c35385ff517b34111e1710ff3b37.js +2 -0
  52. data/application/js/min/c7140ec9475e5bf868b901e0621338d7d162358b.js +3 -0
  53. data/application/js/min/f07f2bd6630ee31e1c2288ec223383d8f0658ba6.js +2 -0
  54. data/application/js/page.js +43 -0
  55. data/application/js/page_browser.js +147 -0
  56. data/application/js/page_entry.js +47 -0
  57. data/application/js/popover.js +99 -0
  58. data/application/js/popover_view.js +56 -0
  59. data/application/js/preview.js +64 -0
  60. data/application/js/progress.js +358 -0
  61. data/application/js/properties.js +90 -0
  62. data/application/js/publish.js +187 -0
  63. data/application/js/require.js +129 -0
  64. data/application/js/sharded_upload.js +206 -0
  65. data/application/js/side_bar.js +30 -0
  66. data/application/js/spontaneous.js +6 -0
  67. data/application/js/state.js +64 -0
  68. data/application/js/status_bar.js +47 -0
  69. data/application/js/top_bar.js +368 -0
  70. data/application/js/types.js +98 -0
  71. data/application/js/upload.js +88 -0
  72. data/application/js/upload_manager.js +319 -0
  73. data/application/js/user.js +37 -0
  74. data/application/js/vendor/.DS_Store +0 -0
  75. data/application/js/vendor/JS.Class-2.1.5/CHANGELOG +283 -0
  76. data/application/js/vendor/JS.Class-2.1.5/MIT-LICENSE +30 -0
  77. data/application/js/vendor/JS.Class-2.1.5/README +30 -0
  78. data/application/js/vendor/JS.Class-2.1.5/min/command.js +1 -0
  79. data/application/js/vendor/JS.Class-2.1.5/min/comparable.js +1 -0
  80. data/application/js/vendor/JS.Class-2.1.5/min/constant_scope.js +1 -0
  81. data/application/js/vendor/JS.Class-2.1.5/min/core.js +1 -0
  82. data/application/js/vendor/JS.Class-2.1.5/min/decorator.js +1 -0
  83. data/application/js/vendor/JS.Class-2.1.5/min/enumerable.js +1 -0
  84. data/application/js/vendor/JS.Class-2.1.5/min/forwardable.js +1 -0
  85. data/application/js/vendor/JS.Class-2.1.5/min/hash.js +1 -0
  86. data/application/js/vendor/JS.Class-2.1.5/min/linked_list.js +1 -0
  87. data/application/js/vendor/JS.Class-2.1.5/min/loader.js +1 -0
  88. data/application/js/vendor/JS.Class-2.1.5/min/method_chain.js +1 -0
  89. data/application/js/vendor/JS.Class-2.1.5/min/observable.js +1 -0
  90. data/application/js/vendor/JS.Class-2.1.5/min/package.js +1 -0
  91. data/application/js/vendor/JS.Class-2.1.5/min/proxy.js +1 -0
  92. data/application/js/vendor/JS.Class-2.1.5/min/ruby.js +1 -0
  93. data/application/js/vendor/JS.Class-2.1.5/min/set.js +1 -0
  94. data/application/js/vendor/JS.Class-2.1.5/min/stack_trace.js +1 -0
  95. data/application/js/vendor/JS.Class-2.1.5/min/state.js +1 -0
  96. data/application/js/vendor/JS.Class-2.1.5/min/stdlib.js +16 -0
  97. data/application/js/vendor/JS.Class-2.1.5/src/command.js +93 -0
  98. data/application/js/vendor/JS.Class-2.1.5/src/comparable.js +37 -0
  99. data/application/js/vendor/JS.Class-2.1.5/src/constant_scope.js +48 -0
  100. data/application/js/vendor/JS.Class-2.1.5/src/core.js +1060 -0
  101. data/application/js/vendor/JS.Class-2.1.5/src/decorator.js +50 -0
  102. data/application/js/vendor/JS.Class-2.1.5/src/enumerable.js +505 -0
  103. data/application/js/vendor/JS.Class-2.1.5/src/forwardable.js +22 -0
  104. data/application/js/vendor/JS.Class-2.1.5/src/hash.js +334 -0
  105. data/application/js/vendor/JS.Class-2.1.5/src/linked_list.js +114 -0
  106. data/application/js/vendor/JS.Class-2.1.5/src/loader.js +553 -0
  107. data/application/js/vendor/JS.Class-2.1.5/src/method_chain.js +172 -0
  108. data/application/js/vendor/JS.Class-2.1.5/src/observable.js +55 -0
  109. data/application/js/vendor/JS.Class-2.1.5/src/package.js +472 -0
  110. data/application/js/vendor/JS.Class-2.1.5/src/proxy.js +58 -0
  111. data/application/js/vendor/JS.Class-2.1.5/src/ruby.js +44 -0
  112. data/application/js/vendor/JS.Class-2.1.5/src/set.js +332 -0
  113. data/application/js/vendor/JS.Class-2.1.5/src/stack_trace.js +151 -0
  114. data/application/js/vendor/JS.Class-2.1.5/src/state.js +95 -0
  115. data/application/js/vendor/JS.Class-2.1.5/src/stdlib.js +2612 -0
  116. data/application/js/vendor/crypto-2.3.0-crypto.js +160 -0
  117. data/application/js/vendor/crypto-2.3.0-sha1.js +91 -0
  118. data/application/js/vendor/diff_match_patch.js +2153 -0
  119. data/application/js/vendor/jquery-1.4.2.min.js +154 -0
  120. data/application/js/vendor/jquery-1.4.3.min.js +166 -0
  121. data/application/js/vendor/jquery-1.5.1.min.js +16 -0
  122. data/application/js/vendor/jquery-1.5.1rc1.min.js +24 -0
  123. data/application/js/vendor/jquery-1.6.2.min.js +18 -0
  124. data/application/js/vendor/jquery-ui-1.8.6.custom.min.js +265 -0
  125. data/application/js/vendor/jquery-ui-1.8.9.custom.min.js +415 -0
  126. data/application/js/vendor/jquery-ui-1.8.custom.min.js +106 -0
  127. data/application/js/vendor/jquery.hotkeys-0.7.9.js +248 -0
  128. data/application/js/vendor/jquery.hotkeys-0.7.9.min.js +19 -0
  129. data/application/js/vendor/jsdiff.js +169 -0
  130. data/application/js/views/box_view.js +229 -0
  131. data/application/js/views/page_piece_view.js +45 -0
  132. data/application/js/views/page_view.js +238 -0
  133. data/application/js/views/piece_view.js +178 -0
  134. data/application/js/views.js +110 -0
  135. data/application/static/editing-0-noise.png +0 -0
  136. data/application/static/editing-1-noise.png +0 -0
  137. data/application/static/editing-texture-1.png +0 -0
  138. data/application/static/editing-texture.png +0 -0
  139. data/application/static/editing-toolbar-shadow-bottom.png +0 -0
  140. data/application/static/editing-toolbar-shadow-top.png +0 -0
  141. data/application/static/favicon.ico +0 -0
  142. data/application/static/inner-glow.png +0 -0
  143. data/application/static/item-buttons.png +0 -0
  144. data/application/static/location-arrow.png +0 -0
  145. data/application/static/logo-400px-transparent.png +0 -0
  146. data/application/static/missing.png +0 -0
  147. data/application/static/orange-down-arrow.png +0 -0
  148. data/application/static/page-browser-next.png +0 -0
  149. data/application/static/paper-texture-dark.png +0 -0
  150. data/application/static/px.gif +0 -0
  151. data/application/static/select-arrow-root.png +0 -0
  152. data/application/static/select-arrow.png +0 -0
  153. data/application/static/slot-down-arrow.png +0 -0
  154. data/application/static/splash.png +0 -0
  155. data/application/static/spontaneous.png +0 -0
  156. data/application/static/spot.png +0 -0
  157. data/application/static/spot.svg +40 -0
  158. data/application/static/texture.png +0 -0
  159. data/application/views/index.erubis +46 -0
  160. data/application/views/login.erubis +69 -0
  161. data/application/views/schema_modification_error.html.erb +61 -0
  162. data/application/views/unsupported.erubis +23 -0
  163. data/bin/limit-upload +5 -0
  164. data/bin/spot +10 -0
  165. data/bin/unlimit-upload +3 -0
  166. data/config/nginx.conf +60 -0
  167. data/db/migrations/20100610142136_init.rb +66 -0
  168. data/db/migrations/20101130104334_timestamps.rb +44 -0
  169. data/db/migrations/20101202113205_site_publishing_flags.rb +12 -0
  170. data/db/migrations/20101206124543_aliases.rb +16 -0
  171. data/db/migrations/20110201133550_visibility.rb +27 -0
  172. data/db/migrations/20110209152710_users_and_groups.rb +58 -0
  173. data/db/migrations/20110215133910_boxes.rb +25 -0
  174. data/db/migrations/20110521114145_remove_slots_and_entries.rb +21 -0
  175. data/db/migrations/20110604192145_rename_schema_id_columns.rb +22 -0
  176. data/db/migrations/20110805141925_rename_site_to_state.rb +11 -0
  177. data/lib/cutaneous/context_helper.rb +82 -0
  178. data/lib/cutaneous/first_pass_parser.rb +23 -0
  179. data/lib/cutaneous/first_pass_renderer.rb +18 -0
  180. data/lib/cutaneous/parser_core.rb +18 -0
  181. data/lib/cutaneous/preview_context.rb +31 -0
  182. data/lib/cutaneous/preview_renderer.rb +15 -0
  183. data/lib/cutaneous/publish_context.rb +9 -0
  184. data/lib/cutaneous/renderer.rb +122 -0
  185. data/lib/cutaneous/request_context.rb +8 -0
  186. data/lib/cutaneous/second_pass_parser.rb +23 -0
  187. data/lib/cutaneous/second_pass_renderer.rb +18 -0
  188. data/lib/cutaneous.rb +47 -0
  189. data/lib/sequel/plugins/content_table_inheritance.rb +196 -0
  190. data/lib/sequel/plugins/yajl_serialization.rb +154 -0
  191. data/lib/spontaneous/application/feature.rb +9 -0
  192. data/lib/spontaneous/application/plugin.rb +13 -0
  193. data/lib/spontaneous/application.rb +8 -0
  194. data/lib/spontaneous/box.rb +232 -0
  195. data/lib/spontaneous/box_style.rb +64 -0
  196. data/lib/spontaneous/change.rb +107 -0
  197. data/lib/spontaneous/cli/adapter.rb +13 -0
  198. data/lib/spontaneous/cli/base.rb +184 -0
  199. data/lib/spontaneous/cli/console.rb +0 -0
  200. data/lib/spontaneous/cli/media.rb +13 -0
  201. data/lib/spontaneous/cli/server.rb +50 -0
  202. data/lib/spontaneous/cli/site.rb +46 -0
  203. data/lib/spontaneous/cli/sync.rb +42 -0
  204. data/lib/spontaneous/cli/tasks.rb +9 -0
  205. data/lib/spontaneous/cli.rb +83 -0
  206. data/lib/spontaneous/collections/box_set.rb +56 -0
  207. data/lib/spontaneous/collections/change_set.rb +43 -0
  208. data/lib/spontaneous/collections/entry_set.rb +83 -0
  209. data/lib/spontaneous/collections/field_set.rb +53 -0
  210. data/lib/spontaneous/collections/prototype_set.rb +131 -0
  211. data/lib/spontaneous/collections/style_set.rb +13 -0
  212. data/lib/spontaneous/config.rb +156 -0
  213. data/lib/spontaneous/constants.rb +24 -0
  214. data/lib/spontaneous/content.rb +113 -0
  215. data/lib/spontaneous/content_query.rb +17 -0
  216. data/lib/spontaneous/errors.rb +48 -0
  217. data/lib/spontaneous/extensions/array.rb +18 -0
  218. data/lib/spontaneous/extensions/class.rb +17 -0
  219. data/lib/spontaneous/extensions/hash.rb +18 -0
  220. data/lib/spontaneous/extensions/json.rb +26 -0
  221. data/lib/spontaneous/extensions/kernel.rb +7 -0
  222. data/lib/spontaneous/extensions/object.rb +30 -0
  223. data/lib/spontaneous/extensions/object_space.rb +12 -0
  224. data/lib/spontaneous/extensions/string.rb +44 -0
  225. data/lib/spontaneous/facet.rb +47 -0
  226. data/lib/spontaneous/field_types/date_field.rb +12 -0
  227. data/lib/spontaneous/field_types/field.rb +252 -0
  228. data/lib/spontaneous/field_types/image_field.rb +329 -0
  229. data/lib/spontaneous/field_types/markdown_field.rb +37 -0
  230. data/lib/spontaneous/field_types/string_field.rb +14 -0
  231. data/lib/spontaneous/field_types.rb +40 -0
  232. data/lib/spontaneous/generators/page/inline.html.cut +1 -0
  233. data/lib/spontaneous/generators/page/page.html.cut.tt +4 -0
  234. data/lib/spontaneous/generators/page/page.rb.tt +9 -0
  235. data/lib/spontaneous/generators/page.rb +38 -0
  236. data/lib/spontaneous/generators/site/.gitignore +4 -0
  237. data/lib/spontaneous/generators/site/Gemfile.tt +31 -0
  238. data/lib/spontaneous/generators/site/Rakefile.tt +6 -0
  239. data/lib/spontaneous/generators/site/config/back.ru +7 -0
  240. data/lib/spontaneous/generators/site/config/boot.rb +19 -0
  241. data/lib/spontaneous/generators/site/config/database.yml.tt +21 -0
  242. data/lib/spontaneous/generators/site/config/deploy.rb.tt +0 -0
  243. data/lib/spontaneous/generators/site/config/environment.rb.tt +8 -0
  244. data/lib/spontaneous/generators/site/config/environments/development.rb.tt +15 -0
  245. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +5 -0
  246. data/lib/spontaneous/generators/site/config/front.ru +8 -0
  247. data/lib/spontaneous/generators/site/config/user_levels.yml +22 -0
  248. data/lib/spontaneous/generators/site/lib/site.rb.tt +4 -0
  249. data/lib/spontaneous/generators/site/lib/tasks/site.rake.tt +8 -0
  250. data/lib/spontaneous/generators/site/public/css/site.css +0 -0
  251. data/lib/spontaneous/generators/site/public/favicon.ico +0 -0
  252. data/lib/spontaneous/generators/site/public/js/.empty_directory +0 -0
  253. data/lib/spontaneous/generators/site/public/js/site.js +0 -0
  254. data/lib/spontaneous/generators/site/public/robots.txt +0 -0
  255. data/lib/spontaneous/generators/site/schema/.map +1 -0
  256. data/lib/spontaneous/generators/site/schema/page.rb.tt +8 -0
  257. data/lib/spontaneous/generators/site/schema/piece.rb.tt +4 -0
  258. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +13 -0
  259. data/lib/spontaneous/generators/site.rb +77 -0
  260. data/lib/spontaneous/generators.rb +23 -0
  261. data/lib/spontaneous/image_size.rb +117 -0
  262. data/lib/spontaneous/json.rb +33 -0
  263. data/lib/spontaneous/layout.rb +15 -0
  264. data/lib/spontaneous/loader.rb +280 -0
  265. data/lib/spontaneous/logger.rb +369 -0
  266. data/lib/spontaneous/media.rb +84 -0
  267. data/lib/spontaneous/page.rb +92 -0
  268. data/lib/spontaneous/page_controller.rb +18 -0
  269. data/lib/spontaneous/page_piece.rb +77 -0
  270. data/lib/spontaneous/paths.rb +30 -0
  271. data/lib/spontaneous/permissions/access_group.rb +50 -0
  272. data/lib/spontaneous/permissions/access_key.rb +35 -0
  273. data/lib/spontaneous/permissions/user.rb +167 -0
  274. data/lib/spontaneous/permissions/user_level.rb +177 -0
  275. data/lib/spontaneous/permissions.rb +55 -0
  276. data/lib/spontaneous/piece.rb +30 -0
  277. data/lib/spontaneous/plugins/aliases.rb +128 -0
  278. data/lib/spontaneous/plugins/allowed_types.rb +173 -0
  279. data/lib/spontaneous/plugins/application/facets.rb +25 -0
  280. data/lib/spontaneous/plugins/application/paths.rb +137 -0
  281. data/lib/spontaneous/plugins/application/render.rb +29 -0
  282. data/lib/spontaneous/plugins/application/serialisation.rb +16 -0
  283. data/lib/spontaneous/plugins/application/state.rb +86 -0
  284. data/lib/spontaneous/plugins/boxes.rb +84 -0
  285. data/lib/spontaneous/plugins/controllers.rb +52 -0
  286. data/lib/spontaneous/plugins/entries.rb +193 -0
  287. data/lib/spontaneous/plugins/entry.rb +51 -0
  288. data/lib/spontaneous/plugins/fields.rb +103 -0
  289. data/lib/spontaneous/plugins/instance_code.rb +18 -0
  290. data/lib/spontaneous/plugins/layouts.rb +87 -0
  291. data/lib/spontaneous/plugins/media.rb +41 -0
  292. data/lib/spontaneous/plugins/page/formats.rb +67 -0
  293. data/lib/spontaneous/plugins/page/request.rb +89 -0
  294. data/lib/spontaneous/plugins/page_search.rb +64 -0
  295. data/lib/spontaneous/plugins/page_tree.rb +25 -0
  296. data/lib/spontaneous/plugins/paths.rb +125 -0
  297. data/lib/spontaneous/plugins/permissions.rb +63 -0
  298. data/lib/spontaneous/plugins/prototypes.rb +84 -0
  299. data/lib/spontaneous/plugins/publishing.rb +255 -0
  300. data/lib/spontaneous/plugins/render.rb +24 -0
  301. data/lib/spontaneous/plugins/schema_hierarchy.rb +76 -0
  302. data/lib/spontaneous/plugins/schema_id.rb +60 -0
  303. data/lib/spontaneous/plugins/schema_title.rb +33 -0
  304. data/lib/spontaneous/plugins/serialisation.rb +67 -0
  305. data/lib/spontaneous/plugins/site/instance.rb +22 -0
  306. data/lib/spontaneous/plugins/site/map.rb +19 -0
  307. data/lib/spontaneous/plugins/site/publishing.rb +74 -0
  308. data/lib/spontaneous/plugins/site/revisions.rb +28 -0
  309. data/lib/spontaneous/plugins/site/selectors.rb +41 -0
  310. data/lib/spontaneous/plugins/site_map.rb +34 -0
  311. data/lib/spontaneous/plugins/styles.rb +119 -0
  312. data/lib/spontaneous/plugins/supertype.rb +11 -0
  313. data/lib/spontaneous/plugins/visibility.rb +151 -0
  314. data/lib/spontaneous/plugins.rb +20 -0
  315. data/lib/spontaneous/prototypes/box_prototype.rb +168 -0
  316. data/lib/spontaneous/prototypes/field_prototype.rb +112 -0
  317. data/lib/spontaneous/prototypes/layout_prototype.rb +17 -0
  318. data/lib/spontaneous/prototypes/style_prototype.rb +42 -0
  319. data/lib/spontaneous/proxy_object.rb +12 -0
  320. data/lib/spontaneous/publishing/fire_and_forget.rb +57 -0
  321. data/lib/spontaneous/publishing/immediate.rb +197 -0
  322. data/lib/spontaneous/publishing/threaded.rb +25 -0
  323. data/lib/spontaneous/publishing.rb +10 -0
  324. data/lib/spontaneous/rack/around_back.rb +44 -0
  325. data/lib/spontaneous/rack/around_front.rb +29 -0
  326. data/lib/spontaneous/rack/around_preview.rb +26 -0
  327. data/lib/spontaneous/rack/assets.rb +98 -0
  328. data/lib/spontaneous/rack/back.rb +729 -0
  329. data/lib/spontaneous/rack/front.rb +41 -0
  330. data/lib/spontaneous/rack/http.rb +18 -0
  331. data/lib/spontaneous/rack/media.rb +29 -0
  332. data/lib/spontaneous/rack/public.rb +232 -0
  333. data/lib/spontaneous/rack/reloader.rb +42 -0
  334. data/lib/spontaneous/rack/static.rb +25 -0
  335. data/lib/spontaneous/rack.rb +55 -0
  336. data/lib/spontaneous/render/context.rb +100 -0
  337. data/lib/spontaneous/render/development_renderer.rb +14 -0
  338. data/lib/spontaneous/render/engine.rb +19 -0
  339. data/lib/spontaneous/render/format/html.rb +5 -0
  340. data/lib/spontaneous/render/format.rb +70 -0
  341. data/lib/spontaneous/render/preview_renderer.rb +18 -0
  342. data/lib/spontaneous/render/published_renderer.rb +54 -0
  343. data/lib/spontaneous/render/publishing_renderer.rb +13 -0
  344. data/lib/spontaneous/render/renderer.rb +46 -0
  345. data/lib/spontaneous/render.rb +173 -0
  346. data/lib/spontaneous/revision.rb +7 -0
  347. data/lib/spontaneous/schema/schema_modification.rb +260 -0
  348. data/lib/spontaneous/schema/uid.rb +221 -0
  349. data/lib/spontaneous/schema.rb +295 -0
  350. data/lib/spontaneous/server.rb +65 -0
  351. data/lib/spontaneous/site.rb +87 -0
  352. data/lib/spontaneous/state.rb +53 -0
  353. data/lib/spontaneous/style.rb +144 -0
  354. data/lib/spontaneous/tasks/database.rake +9 -0
  355. data/lib/spontaneous/tasks.rb +5 -0
  356. data/lib/spontaneous/version.rb +6 -0
  357. data/lib/spontaneous.rb +179 -0
  358. data/spontaneous.gemspec.tmpl +66 -0
  359. data/test/disabled/test_slots.rb +287 -0
  360. data/test/experimental/test_formats.rb +92 -0
  361. data/test/experimental/test_plugins.rb +64 -0
  362. data/test/fixtures/application/css/test.less +5 -0
  363. data/test/fixtures/application/js/test.js +1 -0
  364. data/test/fixtures/application/static/favicon.ico +1 -0
  365. data/test/fixtures/application/static/test.html +1 -0
  366. data/test/fixtures/application/views/index.erubis +1 -0
  367. data/test/fixtures/back/public/test.html +1 -0
  368. data/test/fixtures/back/templates/layouts/standard.html.cut +1 -0
  369. data/test/fixtures/config/config/environment.rb +4 -0
  370. data/test/fixtures/config/config/environments/development.rb +13 -0
  371. data/test/fixtures/config/config/environments/production.rb +22 -0
  372. data/test/fixtures/config/config/environments/staging.rb +2 -0
  373. data/test/fixtures/example_application/Gemfile +6 -0
  374. data/test/fixtures/example_application/Gemfile.lock +76 -0
  375. data/test/fixtures/example_application/Rakefile +6 -0
  376. data/test/fixtures/example_application/config/back.rb +15 -0
  377. data/test/fixtures/example_application/config/back.ru +8 -0
  378. data/test/fixtures/example_application/config/back.yml +8 -0
  379. data/test/fixtures/example_application/config/boot.rb +16 -0
  380. data/test/fixtures/example_application/config/database.yml +24 -0
  381. data/test/fixtures/example_application/config/environment.rb +4 -0
  382. data/test/fixtures/example_application/config/environments/development.rb +16 -0
  383. data/test/fixtures/example_application/config/environments/production.rb +21 -0
  384. data/test/fixtures/example_application/config/environments/staging.rb +1 -0
  385. data/test/fixtures/example_application/config/front.rb +8 -0
  386. data/test/fixtures/example_application/config/front.ru +8 -0
  387. data/test/fixtures/example_application/config/front.yml +8 -0
  388. data/test/fixtures/example_application/config/schema.yml +48 -0
  389. data/test/fixtures/example_application/config/unicorn.rb +1 -0
  390. data/test/fixtures/example_application/config/user_levels.yml +19 -0
  391. data/test/fixtures/example_application/public/css/test.css +0 -0
  392. data/test/fixtures/example_application/public/favicon.ico +1 -0
  393. data/test/fixtures/example_application/public/js/test.js +0 -0
  394. data/test/fixtures/example_application/public/test.html +1 -0
  395. data/test/fixtures/example_application/schema/client_project.rb +18 -0
  396. data/test/fixtures/example_application/schema/client_projects.rb +8 -0
  397. data/test/fixtures/example_application/schema/home_page.rb +22 -0
  398. data/test/fixtures/example_application/schema/info_page.rb +13 -0
  399. data/test/fixtures/example_application/schema/inline_image.rb +11 -0
  400. data/test/fixtures/example_application/schema/page.rb +4 -0
  401. data/test/fixtures/example_application/schema/piece.rb +3 -0
  402. data/test/fixtures/example_application/schema/project.rb +21 -0
  403. data/test/fixtures/example_application/schema/project_image.rb +18 -0
  404. data/test/fixtures/example_application/schema/projects_page.rb +12 -0
  405. data/test/fixtures/example_application/schema/text.rb +8 -0
  406. data/test/fixtures/example_application/templates/client_project/images.html.cut +1 -0
  407. data/test/fixtures/example_application/templates/client_project.html.cut +4 -0
  408. data/test/fixtures/example_application/templates/client_projects.html.cut +6 -0
  409. data/test/fixtures/example_application/templates/info_page/inline.html.cut +0 -0
  410. data/test/fixtures/example_application/templates/inline_image.html.cut +1 -0
  411. data/test/fixtures/example_application/templates/layouts/home.html.cut +15 -0
  412. data/test/fixtures/example_application/templates/layouts/info.html.cut +3 -0
  413. data/test/fixtures/example_application/templates/layouts/project.html.cut +13 -0
  414. data/test/fixtures/example_application/templates/layouts/projects.html.cut +11 -0
  415. data/test/fixtures/example_application/templates/layouts/standard.html.cut +0 -0
  416. data/test/fixtures/example_application/templates/project/inline.html.cut +5 -0
  417. data/test/fixtures/example_application/templates/project.html.cut +5 -0
  418. data/test/fixtures/example_application/templates/project_image.html.cut +1 -0
  419. data/test/fixtures/example_application/templates/text.html.cut +1 -0
  420. data/test/fixtures/images/rose.greyscale.jpg +0 -0
  421. data/test/fixtures/images/rose.jpg +0 -0
  422. data/test/fixtures/images/size.gif +0 -0
  423. data/test/fixtures/images/size.jpg +0 -0
  424. data/test/fixtures/images/size.png24 +0 -0
  425. data/test/fixtures/images/size.png8 +0 -0
  426. data/test/fixtures/layouts/layouts/custom1.html.cut +1 -0
  427. data/test/fixtures/layouts/layouts/custom1.pdf.cut +0 -0
  428. data/test/fixtures/layouts/layouts/custom1.xml.cut +0 -0
  429. data/test/fixtures/layouts/layouts/custom2.html.cut +1 -0
  430. data/test/fixtures/layouts/layouts/custom3.html.cut +0 -0
  431. data/test/fixtures/layouts/layouts/standard.html.cut +1 -0
  432. data/test/fixtures/media/101/003/rose.jpg +0 -0
  433. data/test/fixtures/permissions/config/user_levels.yml +9 -0
  434. data/test/fixtures/permissions/media/image.jpg +0 -0
  435. data/test/fixtures/plugins/schema_plugin/init.rb +1 -0
  436. data/test/fixtures/plugins/schema_plugin/schema/external.rb +5 -0
  437. data/test/fixtures/plugins/schema_plugin/templates/external.html.cut +1 -0
  438. data/test/fixtures/plugins/schema_plugin/templates/from_plugin.html.cut +0 -0
  439. data/test/fixtures/plugins/schema_plugin/templates/layouts/from_plugin.html.cut +0 -0
  440. data/test/fixtures/public/templates/layouts/default.html.cut +1 -0
  441. data/test/fixtures/public/templates/layouts/default.pdf.cut +1 -0
  442. data/test/fixtures/public/templates/layouts/default.rss.cut +1 -0
  443. data/test/fixtures/public/templates/layouts/dynamic.html.cut +1 -0
  444. data/test/fixtures/public/templates/layouts/standard.html.cut +0 -0
  445. data/test/fixtures/schema/before.yml +24 -0
  446. data/test/fixtures/schema/resolvable.yml +12 -0
  447. data/test/fixtures/schema/schema.yml +7 -0
  448. data/test/fixtures/serialisation/class_hash.yaml.erb +53 -0
  449. data/test/fixtures/serialisation/root_hash.yaml.erb +184 -0
  450. data/test/fixtures/sharding/rose.jpg +0 -0
  451. data/test/fixtures/sharding/xaa +0 -0
  452. data/test/fixtures/sharding/xab +0 -0
  453. data/test/fixtures/sharding/xac +0 -0
  454. data/test/fixtures/sharding/xad +0 -0
  455. data/test/fixtures/sharding/xae +0 -0
  456. data/test/fixtures/sharding/xaf +0 -0
  457. data/test/fixtures/sharding/xag +0 -0
  458. data/test/fixtures/styles/box_a/runny.html.cut +0 -0
  459. data/test/fixtures/styles/box_a.html.cut +1 -0
  460. data/test/fixtures/styles/named2.html.cut +1 -0
  461. data/test/fixtures/styles/orange/apple.html.cut +1 -0
  462. data/test/fixtures/styles/template_class/named1.html.cut +1 -0
  463. data/test/fixtures/styles/template_class/results.html.cut +1 -0
  464. data/test/fixtures/styles/template_class/walky.html.cut +0 -0
  465. data/test/fixtures/styles/template_class.epub.cut +0 -0
  466. data/test/fixtures/styles/template_class.html.cut +1 -0
  467. data/test/fixtures/styles/template_class.pdf.cut +0 -0
  468. data/test/fixtures/styles/template_sub_class1.html.cut +1 -0
  469. data/test/fixtures/templates/aliases/a/a_style.html.cut +0 -0
  470. data/test/fixtures/templates/aliases/a/page.html.cut +0 -0
  471. data/test/fixtures/templates/aliases/a_alias/a_alias_style.html.cut +0 -0
  472. data/test/fixtures/templates/aliases/layouts/b.html.cut +1 -0
  473. data/test/fixtures/templates/aliases/layouts/b_alias.html.cut +1 -0
  474. data/test/fixtures/templates/aliases/layouts/c_alias.html.cut +1 -0
  475. data/test/fixtures/templates/boxes/blank_content/things.html.cut +1 -0
  476. data/test/fixtures/templates/boxes/my_box_class/christy.html.cut +1 -0
  477. data/test/fixtures/templates/boxes/thangs.html.cut +1 -0
  478. data/test/fixtures/templates/boxes/with_template_box.html.cut +1 -0
  479. data/test/fixtures/templates/content/include.html.cut +1 -0
  480. data/test/fixtures/templates/content/include_dir.html.cut +1 -0
  481. data/test/fixtures/templates/content/included.epub.cut +1 -0
  482. data/test/fixtures/templates/content/included.html.cut +1 -0
  483. data/test/fixtures/templates/content/partial/included.html.cut +1 -0
  484. data/test/fixtures/templates/content/preprocess.html.cut +1 -0
  485. data/test/fixtures/templates/content/second.html.cut +1 -0
  486. data/test/fixtures/templates/content/template.epub.cut +1 -0
  487. data/test/fixtures/templates/content/template.html.cut +1 -0
  488. data/test/fixtures/templates/default_style_class.html.cut +1 -0
  489. data/test/fixtures/templates/direct.html.cut +1 -0
  490. data/test/fixtures/templates/extended/grandparent.html.cut +10 -0
  491. data/test/fixtures/templates/extended/main.html.cut +6 -0
  492. data/test/fixtures/templates/extended/parent.html.cut +10 -0
  493. data/test/fixtures/templates/layouts/entries.html.cut +7 -0
  494. data/test/fixtures/templates/layouts/page_style.html.cut +1 -0
  495. data/test/fixtures/templates/layouts/params.html.cut +1 -0
  496. data/test/fixtures/templates/layouts/preview_render.html.cut +2 -0
  497. data/test/fixtures/templates/layouts/standard_page.html.cut +1 -0
  498. data/test/fixtures/templates/layouts/subdir_style.html.cut +1 -0
  499. data/test/fixtures/templates/layouts/template_params.html.cut +1 -0
  500. data/test/fixtures/templates/page_class/inline_style.html.cut +1 -0
  501. data/test/fixtures/templates/preview_render/inline.html.cut +0 -0
  502. data/test/fixtures/templates/publishing/layouts/dynamic.html.cut +1 -0
  503. data/test/fixtures/templates/publishing/layouts/static.html.cut +1 -0
  504. data/test/fixtures/templates/template_class/anonymous_style.html.cut +4 -0
  505. data/test/fixtures/templates/template_class/another_template.html.cut +0 -0
  506. data/test/fixtures/templates/template_class/complex_template.html.cut +6 -0
  507. data/test/fixtures/templates/template_class/complex_template.pdf.cut +6 -0
  508. data/test/fixtures/templates/template_class/default_template_style.html.cut +4 -0
  509. data/test/fixtures/templates/template_class/images_with_template.html.cut +5 -0
  510. data/test/fixtures/templates/template_class/slots_template.html.cut +5 -0
  511. data/test/fixtures/templates/template_class/slots_template.pdf.cut +5 -0
  512. data/test/fixtures/templates/template_class/this_template.epub.cut +1 -0
  513. data/test/fixtures/templates/template_class/this_template.html.cut +1 -0
  514. data/test/fixtures/templates/template_class/this_template.pdf.cut +1 -0
  515. data/test/fixtures/templates/with_default_style_class.html.cut +1 -0
  516. data/test/functional/test_application.rb +176 -0
  517. data/test/functional/test_back.rb +902 -0
  518. data/test/functional/test_front.rb +571 -0
  519. data/test/javascript/test_dom.rb +94 -0
  520. data/test/javascript/test_markdown.rb +97 -0
  521. data/test/slow/test_publishing.rb +987 -0
  522. data/test/slow/test_visibility.rb +250 -0
  523. data/test/support/custom_matchers.rb +77 -0
  524. data/test/support/timing.rb +23 -0
  525. data/test/test_helper.rb +164 -0
  526. data/test/test_javascript.rb +34 -0
  527. data/test/ui/test_page_editing.rb +167 -0
  528. data/test/ui_helper.rb +114 -0
  529. data/test/unit/test_alias.rb +254 -0
  530. data/test/unit/test_authentication.rb +510 -0
  531. data/test/unit/test_boxes.rb +497 -0
  532. data/test/unit/test_config.rb +156 -0
  533. data/test/unit/test_content.rb +221 -0
  534. data/test/unit/test_content_inheritance.rb +103 -0
  535. data/test/unit/test_extensions.rb +14 -0
  536. data/test/unit/test_fields.rb +392 -0
  537. data/test/unit/test_generators.rb +97 -0
  538. data/test/unit/test_image_size.rb +25 -0
  539. data/test/unit/test_images.rb +265 -0
  540. data/test/unit/test_layouts.rb +111 -0
  541. data/test/unit/test_logger.rb +80 -0
  542. data/test/unit/test_media.rb +70 -0
  543. data/test/unit/test_page.rb +244 -0
  544. data/test/unit/test_permissions.rb +834 -0
  545. data/test/unit/test_piece.rb +80 -0
  546. data/test/unit/test_prototype_set.rb +192 -0
  547. data/test/unit/test_prototypes.rb +102 -0
  548. data/test/unit/test_render.rb +359 -0
  549. data/test/unit/test_schema.rb +1009 -0
  550. data/test/unit/test_serialisation.rb +215 -0
  551. data/test/unit/test_site.rb +145 -0
  552. data/test/unit/test_structure.rb +85 -0
  553. data/test/unit/test_styles.rb +417 -0
  554. data/test/unit/test_templates.rb +224 -0
  555. data/test/unit/test_type_hierarchy.rb +28 -0
  556. metadata +1017 -0
@@ -0,0 +1,2153 @@
1
+ /**
2
+ * Diff Match and Patch
3
+ *
4
+ * Copyright 2006 Google Inc.
5
+ * http://code.google.com/p/google-diff-match-patch/
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+
20
+ /**
21
+ * @fileoverview Computes the difference between two texts to create a patch.
22
+ * Applies the patch onto another text, allowing for errors.
23
+ * @author fraser@google.com (Neil Fraser)
24
+ */
25
+
26
+ Spontaneous.Diff = (function() {
27
+ /**
28
+ * Class containing the diff, match and patch methods.
29
+ * @constructor
30
+ */
31
+ var diff_match_patch = function() {
32
+
33
+ // Defaults.
34
+ // Redefine these in your program to override the defaults.
35
+
36
+ // Number of seconds to map a diff before giving up (0 for infinity).
37
+ this.Diff_Timeout = 1.0;
38
+ // Cost of an empty edit operation in terms of edit characters.
39
+ this.Diff_EditCost = 4;
40
+ // At what point is no match declared (0.0 = perfection, 1.0 = very loose).
41
+ this.Match_Threshold = 0.5;
42
+ // How far to search for a match (0 = exact location, 1000+ = broad match).
43
+ // A match this many characters away from the expected location will add
44
+ // 1.0 to the score (0.0 is a perfect match).
45
+ this.Match_Distance = 1000;
46
+ // When deleting a large block of text (over ~64 characters), how close does
47
+ // the contents have to match the expected contents. (0.0 = perfection,
48
+ // 1.0 = very loose). Note that Match_Threshold controls how closely the
49
+ // end points of a delete need to match.
50
+ this.Patch_DeleteThreshold = 0.5;
51
+ // Chunk size for context length.
52
+ this.Patch_Margin = 4;
53
+
54
+ // The number of bits in an int.
55
+ this.Match_MaxBits = 32;
56
+ }
57
+
58
+
59
+ // DIFF FUNCTIONS
60
+
61
+
62
+ /**
63
+ * The data structure representing a diff is an array of tuples:
64
+ * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
65
+ * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
66
+ */
67
+ var DIFF_DELETE = -1;
68
+ var DIFF_INSERT = 1;
69
+ var DIFF_EQUAL = 0;
70
+
71
+ /** @typedef {!Array.<number|string>} */
72
+ diff_match_patch.Diff;
73
+
74
+
75
+ /**
76
+ * Find the differences between two texts. Simplifies the problem by stripping
77
+ * any common prefix or suffix off the texts before diffing.
78
+ * @param {string} text1 Old string to be diffed.
79
+ * @param {string} text2 New string to be diffed.
80
+ * @param {boolean=} opt_checklines Optional speedup flag. If present and false,
81
+ * then don't run a line-level diff first to identify the changed areas.
82
+ * Defaults to true, which does a faster, slightly less optimal diff.
83
+ * @param {number} opt_deadline Optional time when the diff should be complete
84
+ * by. Used internally for recursive calls. Users should set DiffTimeout
85
+ * instead.
86
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
87
+ */
88
+ diff_match_patch.prototype.diff_main = function(text1, text2, opt_checklines, opt_deadline) {
89
+ // Set a deadline by which time the diff must be complete.
90
+ if (typeof opt_deadline == 'undefined') {
91
+ if (this.Diff_Timeout <= 0) {
92
+ opt_deadline = Number.MAX_VALUE;
93
+ } else {
94
+ opt_deadline = (new Date).getTime() + this.Diff_Timeout * 1000;
95
+ }
96
+ }
97
+ var deadline = opt_deadline;
98
+
99
+ // Check for null inputs.
100
+ if (text1 == null || text2 == null) {
101
+ throw new Error('Null input. (diff_main)');
102
+ }
103
+
104
+ // Check for equality (speedup).
105
+ if (text1 == text2) {
106
+ if (text1) {
107
+ return [[DIFF_EQUAL, text1]];
108
+ }
109
+ return [];
110
+ }
111
+
112
+ if (typeof opt_checklines == 'undefined') {
113
+ opt_checklines = true;
114
+ }
115
+ var checklines = opt_checklines;
116
+
117
+ // Trim off common prefix (speedup).
118
+ var commonlength = this.diff_commonPrefix(text1, text2);
119
+ var commonprefix = text1.substring(0, commonlength);
120
+ text1 = text1.substring(commonlength);
121
+ text2 = text2.substring(commonlength);
122
+
123
+ // Trim off common suffix (speedup).
124
+ commonlength = this.diff_commonSuffix(text1, text2);
125
+ var commonsuffix = text1.substring(text1.length - commonlength);
126
+ text1 = text1.substring(0, text1.length - commonlength);
127
+ text2 = text2.substring(0, text2.length - commonlength);
128
+
129
+ // Compute the diff on the middle block.
130
+ var diffs = this.diff_compute_(text1, text2, checklines, deadline);
131
+
132
+ // Restore the prefix and suffix.
133
+ if (commonprefix) {
134
+ diffs.unshift([DIFF_EQUAL, commonprefix]);
135
+ }
136
+ if (commonsuffix) {
137
+ diffs.push([DIFF_EQUAL, commonsuffix]);
138
+ }
139
+ this.diff_cleanupMerge(diffs);
140
+ return diffs;
141
+ };
142
+
143
+
144
+ /**
145
+ * Find the differences between two texts. Assumes that the texts do not
146
+ * have any common prefix or suffix.
147
+ * @param {string} text1 Old string to be diffed.
148
+ * @param {string} text2 New string to be diffed.
149
+ * @param {boolean} checklines Speedup flag. If false, then don't run a
150
+ * line-level diff first to identify the changed areas.
151
+ * If true, then run a faster, slightly less optimal diff.
152
+ * @param {number} deadline Time when the diff should be complete by.
153
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
154
+ * @private
155
+ */
156
+ diff_match_patch.prototype.diff_compute_ = function(text1, text2, checklines, deadline) {
157
+ var diffs;
158
+
159
+ if (!text1) {
160
+ // Just add some text (speedup).
161
+ return [[DIFF_INSERT, text2]];
162
+ }
163
+
164
+ if (!text2) {
165
+ // Just delete some text (speedup).
166
+ return [[DIFF_DELETE, text1]];
167
+ }
168
+
169
+ var longtext = text1.length > text2.length ? text1 : text2;
170
+ var shorttext = text1.length > text2.length ? text2 : text1;
171
+ var i = longtext.indexOf(shorttext);
172
+ if (i != -1) {
173
+ // Shorter text is inside the longer text (speedup).
174
+ diffs = [[DIFF_INSERT, longtext.substring(0, i)],
175
+ [DIFF_EQUAL, shorttext],
176
+ [DIFF_INSERT, longtext.substring(i + shorttext.length)]];
177
+ // Swap insertions for deletions if diff is reversed.
178
+ if (text1.length > text2.length) {
179
+ diffs[0][0] = diffs[2][0] = DIFF_DELETE;
180
+ }
181
+ return diffs;
182
+ }
183
+
184
+ if (shorttext.length == 1) {
185
+ // Single character string.
186
+ // After the previous speedup, the character can't be an equality.
187
+ return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
188
+ }
189
+ longtext = shorttext = null; // Garbage collect.
190
+
191
+ // Check to see if the problem can be split in two.
192
+ var hm = this.diff_halfMatch_(text1, text2);
193
+ if (hm) {
194
+ // A half-match was found, sort out the return data.
195
+ var text1_a = hm[0];
196
+ var text1_b = hm[1];
197
+ var text2_a = hm[2];
198
+ var text2_b = hm[3];
199
+ var mid_common = hm[4];
200
+ // Send both pairs off for separate processing.
201
+ var diffs_a = this.diff_main(text1_a, text2_a, checklines, deadline);
202
+ var diffs_b = this.diff_main(text1_b, text2_b, checklines, deadline);
203
+ // Merge the results.
204
+ return diffs_a.concat([[DIFF_EQUAL, mid_common]], diffs_b);
205
+ }
206
+
207
+ if (checklines && text1.length > 100 && text2.length > 100) {
208
+ return this.diff_lineMode_(text1, text2, deadline);
209
+ }
210
+
211
+ return this.diff_bisect_(text1, text2, deadline);
212
+ };
213
+
214
+
215
+ /**
216
+ * Do a quick line-level diff on both strings, then rediff the parts for
217
+ * greater accuracy.
218
+ * This speedup can produce non-minimal diffs.
219
+ * @param {string} text1 Old string to be diffed.
220
+ * @param {string} text2 New string to be diffed.
221
+ * @param {number} deadline Time when the diff should be complete by.
222
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
223
+ * @private
224
+ */
225
+ diff_match_patch.prototype.diff_lineMode_ = function(text1, text2, deadline) {
226
+ // Scan the text on a line-by-line basis first.
227
+ var a = this.diff_linesToChars_(text1, text2);
228
+ text1 = /** @type {string} */(a[0]);
229
+ text2 = /** @type {string} */(a[1]);
230
+ var linearray = /** @type {!Array.<string>} */(a[2]);
231
+
232
+ var diffs = this.diff_bisect_(text1, text2, deadline);
233
+
234
+ // Convert the diff back to original text.
235
+ this.diff_charsToLines_(diffs, linearray);
236
+ // Eliminate freak matches (e.g. blank lines)
237
+ this.diff_cleanupSemantic(diffs);
238
+
239
+ // Rediff any replacement blocks, this time character-by-character.
240
+ // Add a dummy entry at the end.
241
+ diffs.push([DIFF_EQUAL, '']);
242
+ var pointer = 0;
243
+ var count_delete = 0;
244
+ var count_insert = 0;
245
+ var text_delete = '';
246
+ var text_insert = '';
247
+ while (pointer < diffs.length) {
248
+ switch (diffs[pointer][0]) {
249
+ case DIFF_INSERT:
250
+ count_insert++;
251
+ text_insert += diffs[pointer][1];
252
+ break;
253
+ case DIFF_DELETE:
254
+ count_delete++;
255
+ text_delete += diffs[pointer][1];
256
+ break;
257
+ case DIFF_EQUAL:
258
+ // Upon reaching an equality, check for prior redundancies.
259
+ if (count_delete >= 1 && count_insert >= 1) {
260
+ // Delete the offending records and add the merged ones.
261
+ var a = this.diff_main(text_delete, text_insert, false, deadline);
262
+ diffs.splice(pointer - count_delete - count_insert,
263
+ count_delete + count_insert);
264
+ pointer = pointer - count_delete - count_insert;
265
+ for (var j = a.length - 1; j >= 0; j--) {
266
+ diffs.splice(pointer, 0, a[j]);
267
+ }
268
+ pointer = pointer + a.length;
269
+ }
270
+ count_insert = 0;
271
+ count_delete = 0;
272
+ text_delete = '';
273
+ text_insert = '';
274
+ break;
275
+ }
276
+ pointer++;
277
+ }
278
+ diffs.pop(); // Remove the dummy entry at the end.
279
+
280
+ return diffs;
281
+ };
282
+
283
+
284
+ /**
285
+ * Find the 'middle snake' of a diff, split the problem in two
286
+ * and return the recursively constructed diff.
287
+ * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
288
+ * @param {string} text1 Old string to be diffed.
289
+ * @param {string} text2 New string to be diffed.
290
+ * @param {number} deadline Time at which to bail if not yet complete.
291
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
292
+ * @private
293
+ */
294
+ diff_match_patch.prototype.diff_bisect_ = function(text1, text2, deadline) {
295
+ // Cache the text lengths to prevent multiple calls.
296
+ var text1_length = text1.length;
297
+ var text2_length = text2.length;
298
+ var max_d = Math.ceil((text1_length + text2_length) / 2);
299
+ var v_offset = max_d;
300
+ var v_length = 2 * max_d;
301
+ var v1 = new Array(v_length);
302
+ var v2 = new Array(v_length);
303
+ // Setting all elements to -1 is faster in Chrome & Firefox than mixing
304
+ // integers and undefined.
305
+ for (var x = 0; x < v_length; x++) {
306
+ v1[x] = -1;
307
+ v2[x] = -1;
308
+ }
309
+ v1[v_offset + 1] = 0;
310
+ v2[v_offset + 1] = 0;
311
+ var delta = text1_length - text2_length;
312
+ // If the total number of characters is odd, then the front path will collide
313
+ // with the reverse path.
314
+ var front = (delta % 2 != 0);
315
+ // Offsets for start and end of k loop.
316
+ // Prevents mapping of space beyond the grid.
317
+ var k1start = 0;
318
+ var k1end = 0;
319
+ var k2start = 0;
320
+ var k2end = 0;
321
+ for (var d = 0; d < max_d; d++) {
322
+ // Bail out if deadline is reached.
323
+ if ((new Date()).getTime() > deadline) {
324
+ break;
325
+ }
326
+
327
+ // Walk the front path one step.
328
+ for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
329
+ var k1_offset = v_offset + k1;
330
+ var x1;
331
+ if (k1 == -d || k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1]) {
332
+ x1 = v1[k1_offset + 1];
333
+ } else {
334
+ x1 = v1[k1_offset - 1] + 1;
335
+ }
336
+ var y1 = x1 - k1;
337
+ while (x1 < text1_length && y1 < text2_length &&
338
+ text1.charAt(x1) == text2.charAt(y1)) {
339
+ x1++;
340
+ y1++;
341
+ }
342
+ v1[k1_offset] = x1;
343
+ if (x1 > text1_length) {
344
+ // Ran off the right of the graph.
345
+ k1end += 2;
346
+ } else if (y1 > text2_length) {
347
+ // Ran off the bottom of the graph.
348
+ k1start += 2;
349
+ } else if (front) {
350
+ var k2_offset = v_offset + delta - k1;
351
+ if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) {
352
+ // Mirror x2 onto top-left coordinate system.
353
+ var x2 = text1_length - v2[k2_offset];
354
+ if (x1 >= x2) {
355
+ // Overlap detected.
356
+ return this.diff_bisectSplit_(text1, text2, x1, y1, deadline);
357
+ }
358
+ }
359
+ }
360
+ }
361
+
362
+ // Walk the reverse path one step.
363
+ for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
364
+ var k2_offset = v_offset + k2;
365
+ var x2;
366
+ if (k2 == -d || k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1]) {
367
+ x2 = v2[k2_offset + 1];
368
+ } else {
369
+ x2 = v2[k2_offset - 1] + 1;
370
+ }
371
+ var y2 = x2 - k2;
372
+ while (x2 < text1_length && y2 < text2_length &&
373
+ text1.charAt(text1_length - x2 - 1) ==
374
+ text2.charAt(text2_length - y2 - 1)) {
375
+ x2++;
376
+ y2++;
377
+ }
378
+ v2[k2_offset] = x2;
379
+ if (x2 > text1_length) {
380
+ // Ran off the left of the graph.
381
+ k2end += 2;
382
+ } else if (y2 > text2_length) {
383
+ // Ran off the top of the graph.
384
+ k2start += 2;
385
+ } else if (!front) {
386
+ var k1_offset = v_offset + delta - k2;
387
+ if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) {
388
+ var x1 = v1[k1_offset];
389
+ var y1 = v_offset + x1 - k1_offset;
390
+ // Mirror x2 onto top-left coordinate system.
391
+ x2 = text1_length - x2;
392
+ if (x1 >= x2) {
393
+ // Overlap detected.
394
+ return this.diff_bisectSplit_(text1, text2, x1, y1, deadline);
395
+ }
396
+ }
397
+ }
398
+ }
399
+ }
400
+ // Diff took too long and hit the deadline or
401
+ // number of diffs equals number of characters, no commonality at all.
402
+ return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
403
+ };
404
+
405
+
406
+ /**
407
+ * Given the location of the 'middle snake', split the diff in two parts
408
+ * and recurse.
409
+ * @param {string} text1 Old string to be diffed.
410
+ * @param {string} text2 New string to be diffed.
411
+ * @param {number} x Index of split point in text1.
412
+ * @param {number} y Index of split point in text2.
413
+ * @param {number} deadline Time at which to bail if not yet complete.
414
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
415
+ * @private
416
+ */
417
+ diff_match_patch.prototype.diff_bisectSplit_ = function(text1, text2, x, y, deadline) {
418
+ var text1a = text1.substring(0, x);
419
+ var text2a = text2.substring(0, y);
420
+ var text1b = text1.substring(x);
421
+ var text2b = text2.substring(y);
422
+
423
+ // Compute both diffs serially.
424
+ var diffs = this.diff_main(text1a, text2a, false, deadline);
425
+ var diffsb = this.diff_main(text1b, text2b, false, deadline);
426
+
427
+ return diffs.concat(diffsb);
428
+ };
429
+
430
+
431
+ /**
432
+ * Split two texts into an array of strings. Reduce the texts to a string of
433
+ * hashes where each Unicode character represents one line.
434
+ * @param {string} text1 First string.
435
+ * @param {string} text2 Second string.
436
+ * @return {!Array.<string|!Array.<string>>} Three element Array, containing the
437
+ * encoded text1, the encoded text2 and the array of unique strings. The
438
+ * zeroth element of the array of unique strings is intentionally blank.
439
+ * @private
440
+ */
441
+ diff_match_patch.prototype.diff_linesToChars_ = function(text1, text2) {
442
+ var lineArray = []; // e.g. lineArray[4] == 'Hello\n'
443
+ var lineHash = {}; // e.g. lineHash['Hello\n'] == 4
444
+
445
+ // '\x00' is a valid character, but various debuggers don't like it.
446
+ // So we'll insert a junk entry to avoid generating a null character.
447
+ lineArray[0] = '';
448
+
449
+ /**
450
+ * Split a text into an array of strings. Reduce the texts to a string of
451
+ * hashes where each Unicode character represents one line.
452
+ * Modifies linearray and linehash through being a closure.
453
+ * @param {string} text String to encode.
454
+ * @return {string} Encoded string.
455
+ * @private
456
+ */
457
+ function diff_linesToCharsMunge_(text) {
458
+ var chars = '';
459
+ // Walk the text, pulling out a substring for each line.
460
+ // text.split('\n') would would temporarily double our memory footprint.
461
+ // Modifying text would create many large strings to garbage collect.
462
+ var lineStart = 0;
463
+ var lineEnd = -1;
464
+ // Keeping our own length variable is faster than looking it up.
465
+ var lineArrayLength = lineArray.length;
466
+ while (lineEnd < text.length - 1) {
467
+ lineEnd = text.indexOf('\n', lineStart);
468
+ if (lineEnd == -1) {
469
+ lineEnd = text.length - 1;
470
+ }
471
+ var line = text.substring(lineStart, lineEnd + 1);
472
+ lineStart = lineEnd + 1;
473
+
474
+ if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) :
475
+ (lineHash[line] !== undefined)) {
476
+ chars += String.fromCharCode(lineHash[line]);
477
+ } else {
478
+ chars += String.fromCharCode(lineArrayLength);
479
+ lineHash[line] = lineArrayLength;
480
+ lineArray[lineArrayLength++] = line;
481
+ }
482
+ }
483
+ return chars;
484
+ }
485
+
486
+ var chars1 = diff_linesToCharsMunge_(text1);
487
+ var chars2 = diff_linesToCharsMunge_(text2);
488
+ return [chars1, chars2, lineArray];
489
+ };
490
+
491
+
492
+ /**
493
+ * Rehydrate the text in a diff from a string of line hashes to real lines of
494
+ * text.
495
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
496
+ * @param {!Array.<string>} lineArray Array of unique strings.
497
+ * @private
498
+ */
499
+ diff_match_patch.prototype.diff_charsToLines_ = function(diffs, lineArray) {
500
+ for (var x = 0; x < diffs.length; x++) {
501
+ var chars = diffs[x][1];
502
+ var text = [];
503
+ for (var y = 0; y < chars.length; y++) {
504
+ text[y] = lineArray[chars.charCodeAt(y)];
505
+ }
506
+ diffs[x][1] = text.join('');
507
+ }
508
+ };
509
+
510
+
511
+ /**
512
+ * Determine the common prefix of two strings.
513
+ * @param {string} text1 First string.
514
+ * @param {string} text2 Second string.
515
+ * @return {number} The number of characters common to the start of each
516
+ * string.
517
+ */
518
+ diff_match_patch.prototype.diff_commonPrefix = function(text1, text2) {
519
+ // Quick check for common null cases.
520
+ if (!text1 || !text2 || text1.charAt(0) != text2.charAt(0)) {
521
+ return 0;
522
+ }
523
+ // Binary search.
524
+ // Performance analysis: http://neil.fraser.name/news/2007/10/09/
525
+ var pointermin = 0;
526
+ var pointermax = Math.min(text1.length, text2.length);
527
+ var pointermid = pointermax;
528
+ var pointerstart = 0;
529
+ while (pointermin < pointermid) {
530
+ if (text1.substring(pointerstart, pointermid) ==
531
+ text2.substring(pointerstart, pointermid)) {
532
+ pointermin = pointermid;
533
+ pointerstart = pointermin;
534
+ } else {
535
+ pointermax = pointermid;
536
+ }
537
+ pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
538
+ }
539
+ return pointermid;
540
+ };
541
+
542
+
543
+ /**
544
+ * Determine the common suffix of two strings.
545
+ * @param {string} text1 First string.
546
+ * @param {string} text2 Second string.
547
+ * @return {number} The number of characters common to the end of each string.
548
+ */
549
+ diff_match_patch.prototype.diff_commonSuffix = function(text1, text2) {
550
+ // Quick check for common null cases.
551
+ if (!text1 || !text2 ||
552
+ text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) {
553
+ return 0;
554
+ }
555
+ // Binary search.
556
+ // Performance analysis: http://neil.fraser.name/news/2007/10/09/
557
+ var pointermin = 0;
558
+ var pointermax = Math.min(text1.length, text2.length);
559
+ var pointermid = pointermax;
560
+ var pointerend = 0;
561
+ while (pointermin < pointermid) {
562
+ if (text1.substring(text1.length - pointermid, text1.length - pointerend) ==
563
+ text2.substring(text2.length - pointermid, text2.length - pointerend)) {
564
+ pointermin = pointermid;
565
+ pointerend = pointermin;
566
+ } else {
567
+ pointermax = pointermid;
568
+ }
569
+ pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
570
+ }
571
+ return pointermid;
572
+ };
573
+
574
+
575
+ /**
576
+ * Determine if the suffix of one string is the prefix of another.
577
+ * @param {string} text1 First string.
578
+ * @param {string} text2 Second string.
579
+ * @return {number} The number of characters common to the end of the first
580
+ * string and the start of the second string.
581
+ * @private
582
+ */
583
+ diff_match_patch.prototype.diff_commonOverlap_ = function(text1, text2) {
584
+ // Cache the text lengths to prevent multiple calls.
585
+ var text1_length = text1.length;
586
+ var text2_length = text2.length;
587
+ // Eliminate the null case.
588
+ if (text1_length == 0 || text2_length == 0) {
589
+ return 0;
590
+ }
591
+ // Truncate the longer string.
592
+ if (text1_length > text2_length) {
593
+ text1 = text1.substring(text1_length - text2_length);
594
+ } else if (text1_length < text2_length) {
595
+ text2 = text2.substring(0, text1_length);
596
+ }
597
+ var text_length = Math.min(text1_length, text2_length);
598
+ // Quick check for the worst case.
599
+ if (text1 == text2) {
600
+ return text_length;
601
+ }
602
+
603
+ // Start by looking for a single character match
604
+ // and increase length until no match is found.
605
+ // Performance analysis: http://neil.fraser.name/news/2010/11/04/
606
+ var best = 0;
607
+ var length = 1;
608
+ while (true) {
609
+ var pattern = text1.substring(text_length - length);
610
+ var found = text2.indexOf(pattern);
611
+ if (found == -1) {
612
+ return best;
613
+ }
614
+ length += found;
615
+ if (found == 0 || text1.substring(text_length - length) ==
616
+ text2.substring(0, length)) {
617
+ best = length;
618
+ length++;
619
+ }
620
+ }
621
+ };
622
+
623
+
624
+ /**
625
+ * Do the two texts share a substring which is at least half the length of the
626
+ * longer text?
627
+ * This speedup can produce non-minimal diffs.
628
+ * @param {string} text1 First string.
629
+ * @param {string} text2 Second string.
630
+ * @return {Array.<string>} Five element Array, containing the prefix of
631
+ * text1, the suffix of text1, the prefix of text2, the suffix of
632
+ * text2 and the common middle. Or null if there was no match.
633
+ * @private
634
+ */
635
+ diff_match_patch.prototype.diff_halfMatch_ = function(text1, text2) {
636
+ if (this.Diff_Timeout <= 0) {
637
+ // Don't risk returning a non-optimal diff if we have unlimited time.
638
+ return null;
639
+ }
640
+ var longtext = text1.length > text2.length ? text1 : text2;
641
+ var shorttext = text1.length > text2.length ? text2 : text1;
642
+ if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {
643
+ return null; // Pointless.
644
+ }
645
+ var dmp = this; // 'this' becomes 'window' in a closure.
646
+
647
+ /**
648
+ * Does a substring of shorttext exist within longtext such that the substring
649
+ * is at least half the length of longtext?
650
+ * Closure, but does not reference any external variables.
651
+ * @param {string} longtext Longer string.
652
+ * @param {string} shorttext Shorter string.
653
+ * @param {number} i Start index of quarter length substring within longtext.
654
+ * @return {Array.<string>} Five element Array, containing the prefix of
655
+ * longtext, the suffix of longtext, the prefix of shorttext, the suffix
656
+ * of shorttext and the common middle. Or null if there was no match.
657
+ * @private
658
+ */
659
+ function diff_halfMatchI_(longtext, shorttext, i) {
660
+ // Start with a 1/4 length substring at position i as a seed.
661
+ var seed = longtext.substring(i, i + Math.floor(longtext.length / 4));
662
+ var j = -1;
663
+ var best_common = '';
664
+ var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;
665
+ while ((j = shorttext.indexOf(seed, j + 1)) != -1) {
666
+ var prefixLength = dmp.diff_commonPrefix(longtext.substring(i),
667
+ shorttext.substring(j));
668
+ var suffixLength = dmp.diff_commonSuffix(longtext.substring(0, i),
669
+ shorttext.substring(0, j));
670
+ if (best_common.length < suffixLength + prefixLength) {
671
+ best_common = shorttext.substring(j - suffixLength, j) +
672
+ shorttext.substring(j, j + prefixLength);
673
+ best_longtext_a = longtext.substring(0, i - suffixLength);
674
+ best_longtext_b = longtext.substring(i + prefixLength);
675
+ best_shorttext_a = shorttext.substring(0, j - suffixLength);
676
+ best_shorttext_b = shorttext.substring(j + prefixLength);
677
+ }
678
+ }
679
+ if (best_common.length * 2 >= longtext.length) {
680
+ return [best_longtext_a, best_longtext_b,
681
+ best_shorttext_a, best_shorttext_b, best_common];
682
+ } else {
683
+ return null;
684
+ }
685
+ }
686
+
687
+ // First check if the second quarter is the seed for a half-match.
688
+ var hm1 = diff_halfMatchI_(longtext, shorttext,
689
+ Math.ceil(longtext.length / 4));
690
+ // Check again based on the third quarter.
691
+ var hm2 = diff_halfMatchI_(longtext, shorttext,
692
+ Math.ceil(longtext.length / 2));
693
+ var hm;
694
+ if (!hm1 && !hm2) {
695
+ return null;
696
+ } else if (!hm2) {
697
+ hm = hm1;
698
+ } else if (!hm1) {
699
+ hm = hm2;
700
+ } else {
701
+ // Both matched. Select the longest.
702
+ hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
703
+ }
704
+
705
+ // A half-match was found, sort out the return data.
706
+ var text1_a, text1_b, text2_a, text2_b;
707
+ if (text1.length > text2.length) {
708
+ text1_a = hm[0];
709
+ text1_b = hm[1];
710
+ text2_a = hm[2];
711
+ text2_b = hm[3];
712
+ } else {
713
+ text2_a = hm[0];
714
+ text2_b = hm[1];
715
+ text1_a = hm[2];
716
+ text1_b = hm[3];
717
+ }
718
+ var mid_common = hm[4];
719
+ return [text1_a, text1_b, text2_a, text2_b, mid_common];
720
+ };
721
+
722
+
723
+ /**
724
+ * Reduce the number of edits by eliminating semantically trivial equalities.
725
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
726
+ */
727
+ diff_match_patch.prototype.diff_cleanupSemantic = function(diffs) {
728
+ var changes = false;
729
+ var equalities = []; // Stack of indices where equalities are found.
730
+ var equalitiesLength = 0; // Keeping our own length var is faster in JS.
731
+ /** @type {?string} */
732
+ var lastequality = null; // Always equal to equalities[equalitiesLength-1][1]
733
+ var pointer = 0; // Index of current position.
734
+ // Number of characters that changed prior to the equality.
735
+ var length_insertions1 = 0;
736
+ var length_deletions1 = 0;
737
+ // Number of characters that changed after the equality.
738
+ var length_insertions2 = 0;
739
+ var length_deletions2 = 0;
740
+ while (pointer < diffs.length) {
741
+ if (diffs[pointer][0] == DIFF_EQUAL) { // Equality found.
742
+ equalities[equalitiesLength++] = pointer;
743
+ length_insertions1 = length_insertions2;
744
+ length_deletions1 = length_deletions2;
745
+ length_insertions2 = 0;
746
+ length_deletions2 = 0;
747
+ lastequality = /** @type {string} */(diffs[pointer][1]);
748
+ } else { // An insertion or deletion.
749
+ if (diffs[pointer][0] == DIFF_INSERT) {
750
+ length_insertions2 += diffs[pointer][1].length;
751
+ } else {
752
+ length_deletions2 += diffs[pointer][1].length;
753
+ }
754
+ // Eliminate an equality that is smaller or equal to the edits on both
755
+ // sides of it.
756
+ if (lastequality !== null && (lastequality.length <=
757
+ Math.max(length_insertions1, length_deletions1)) &&
758
+ (lastequality.length <= Math.max(length_insertions2,
759
+ length_deletions2))) {
760
+ // Duplicate record.
761
+ diffs.splice(equalities[equalitiesLength - 1], 0,
762
+ [DIFF_DELETE, lastequality]);
763
+ // Change second copy to insert.
764
+ diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
765
+ // Throw away the equality we just deleted.
766
+ equalitiesLength--;
767
+ // Throw away the previous equality (it needs to be reevaluated).
768
+ equalitiesLength--;
769
+ pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
770
+ length_insertions1 = 0; // Reset the counters.
771
+ length_deletions1 = 0;
772
+ length_insertions2 = 0;
773
+ length_deletions2 = 0;
774
+ lastequality = null;
775
+ changes = true;
776
+ }
777
+ }
778
+ pointer++;
779
+ }
780
+
781
+ // Normalize the diff.
782
+ if (changes) {
783
+ this.diff_cleanupMerge(diffs);
784
+ }
785
+ this.diff_cleanupSemanticLossless(diffs);
786
+
787
+ // Find any overlaps between deletions and insertions.
788
+ // e.g: <del>abcxxx</del><ins>xxxdef</ins>
789
+ // -> <del>abc</del>xxx<ins>def</ins>
790
+ // Only extract an overlap if it is as big as the edit ahead or behind it.
791
+ pointer = 1;
792
+ while (pointer < diffs.length) {
793
+ if (diffs[pointer - 1][0] == DIFF_DELETE &&
794
+ diffs[pointer][0] == DIFF_INSERT) {
795
+ var deletion = /** @type {string} */(diffs[pointer - 1][1]);
796
+ var insertion = /** @type {string} */(diffs[pointer][1]);
797
+ var overlap_length = this.diff_commonOverlap_(deletion, insertion);
798
+ if (overlap_length >= deletion.length / 2 ||
799
+ overlap_length >= insertion.length / 2) {
800
+ // Overlap found. Insert an equality and trim the surrounding edits.
801
+ diffs.splice(pointer, 0,
802
+ [DIFF_EQUAL, insertion.substring(0, overlap_length)]);
803
+ diffs[pointer - 1][1] =
804
+ deletion.substring(0, deletion.length - overlap_length);
805
+ diffs[pointer + 1][1] = insertion.substring(overlap_length);
806
+ pointer++;
807
+ }
808
+ pointer++;
809
+ }
810
+ pointer++;
811
+ }
812
+ };
813
+
814
+
815
+ /**
816
+ * Look for single edits surrounded on both sides by equalities
817
+ * which can be shifted sideways to align the edit to a word boundary.
818
+ * e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
819
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
820
+ */
821
+ diff_match_patch.prototype.diff_cleanupSemanticLossless = function(diffs) {
822
+ // Define some regex patterns for matching boundaries.
823
+ var punctuation = /[^a-zA-Z0-9]/;
824
+ var whitespace = /\s/;
825
+ var linebreak = /[\r\n]/;
826
+ var blanklineEnd = /\n\r?\n$/;
827
+ var blanklineStart = /^\r?\n\r?\n/;
828
+
829
+ /**
830
+ * Given two strings, compute a score representing whether the internal
831
+ * boundary falls on logical boundaries.
832
+ * Scores range from 5 (best) to 0 (worst).
833
+ * Closure, makes reference to regex patterns defined above.
834
+ * @param {string} one First string.
835
+ * @param {string} two Second string.
836
+ * @return {number} The score.
837
+ * @private
838
+ */
839
+ function diff_cleanupSemanticScore_(one, two) {
840
+ if (!one || !two) {
841
+ // Edges are the best.
842
+ return 5;
843
+ }
844
+
845
+ // Each port of this function behaves slightly differently due to
846
+ // subtle differences in each language's definition of things like
847
+ // 'whitespace'. Since this function's purpose is largely cosmetic,
848
+ // the choice has been made to use each language's native features
849
+ // rather than force total conformity.
850
+ var score = 0;
851
+ // One point for non-alphanumeric.
852
+ if (one.charAt(one.length - 1).match(punctuation) ||
853
+ two.charAt(0).match(punctuation)) {
854
+ score++;
855
+ // Two points for whitespace.
856
+ if (one.charAt(one.length - 1).match(whitespace) ||
857
+ two.charAt(0).match(whitespace)) {
858
+ score++;
859
+ // Three points for line breaks.
860
+ if (one.charAt(one.length - 1).match(linebreak) ||
861
+ two.charAt(0).match(linebreak)) {
862
+ score++;
863
+ // Four points for blank lines.
864
+ if (one.match(blanklineEnd) || two.match(blanklineStart)) {
865
+ score++;
866
+ }
867
+ }
868
+ }
869
+ }
870
+ return score;
871
+ }
872
+
873
+ var pointer = 1;
874
+ // Intentionally ignore the first and last element (don't need checking).
875
+ while (pointer < diffs.length - 1) {
876
+ if (diffs[pointer - 1][0] == DIFF_EQUAL &&
877
+ diffs[pointer + 1][0] == DIFF_EQUAL) {
878
+ // This is a single edit surrounded by equalities.
879
+ var equality1 = /** @type {string} */(diffs[pointer - 1][1]);
880
+ var edit = /** @type {string} */(diffs[pointer][1]);
881
+ var equality2 = /** @type {string} */(diffs[pointer + 1][1]);
882
+
883
+ // First, shift the edit as far left as possible.
884
+ var commonOffset = this.diff_commonSuffix(equality1, edit);
885
+ if (commonOffset) {
886
+ var commonString = edit.substring(edit.length - commonOffset);
887
+ equality1 = equality1.substring(0, equality1.length - commonOffset);
888
+ edit = commonString + edit.substring(0, edit.length - commonOffset);
889
+ equality2 = commonString + equality2;
890
+ }
891
+
892
+ // Second, step character by character right, looking for the best fit.
893
+ var bestEquality1 = equality1;
894
+ var bestEdit = edit;
895
+ var bestEquality2 = equality2;
896
+ var bestScore = diff_cleanupSemanticScore_(equality1, edit) +
897
+ diff_cleanupSemanticScore_(edit, equality2);
898
+ while (edit.charAt(0) === equality2.charAt(0)) {
899
+ equality1 += edit.charAt(0);
900
+ edit = edit.substring(1) + equality2.charAt(0);
901
+ equality2 = equality2.substring(1);
902
+ var score = diff_cleanupSemanticScore_(equality1, edit) +
903
+ diff_cleanupSemanticScore_(edit, equality2);
904
+ // The >= encourages trailing rather than leading whitespace on edits.
905
+ if (score >= bestScore) {
906
+ bestScore = score;
907
+ bestEquality1 = equality1;
908
+ bestEdit = edit;
909
+ bestEquality2 = equality2;
910
+ }
911
+ }
912
+
913
+ if (diffs[pointer - 1][1] != bestEquality1) {
914
+ // We have an improvement, save it back to the diff.
915
+ if (bestEquality1) {
916
+ diffs[pointer - 1][1] = bestEquality1;
917
+ } else {
918
+ diffs.splice(pointer - 1, 1);
919
+ pointer--;
920
+ }
921
+ diffs[pointer][1] = bestEdit;
922
+ if (bestEquality2) {
923
+ diffs[pointer + 1][1] = bestEquality2;
924
+ } else {
925
+ diffs.splice(pointer + 1, 1);
926
+ pointer--;
927
+ }
928
+ }
929
+ }
930
+ pointer++;
931
+ }
932
+ };
933
+
934
+
935
+ /**
936
+ * Reduce the number of edits by eliminating operationally trivial equalities.
937
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
938
+ */
939
+ diff_match_patch.prototype.diff_cleanupEfficiency = function(diffs) {
940
+ var changes = false;
941
+ var equalities = []; // Stack of indices where equalities are found.
942
+ var equalitiesLength = 0; // Keeping our own length var is faster in JS.
943
+ var lastequality = ''; // Always equal to equalities[equalitiesLength-1][1]
944
+ var pointer = 0; // Index of current position.
945
+ // Is there an insertion operation before the last equality.
946
+ var pre_ins = false;
947
+ // Is there a deletion operation before the last equality.
948
+ var pre_del = false;
949
+ // Is there an insertion operation after the last equality.
950
+ var post_ins = false;
951
+ // Is there a deletion operation after the last equality.
952
+ var post_del = false;
953
+ while (pointer < diffs.length) {
954
+ if (diffs[pointer][0] == DIFF_EQUAL) { // Equality found.
955
+ if (diffs[pointer][1].length < this.Diff_EditCost &&
956
+ (post_ins || post_del)) {
957
+ // Candidate found.
958
+ equalities[equalitiesLength++] = pointer;
959
+ pre_ins = post_ins;
960
+ pre_del = post_del;
961
+ lastequality = diffs[pointer][1];
962
+ } else {
963
+ // Not a candidate, and can never become one.
964
+ equalitiesLength = 0;
965
+ lastequality = '';
966
+ }
967
+ post_ins = post_del = false;
968
+ } else { // An insertion or deletion.
969
+ if (diffs[pointer][0] == DIFF_DELETE) {
970
+ post_del = true;
971
+ } else {
972
+ post_ins = true;
973
+ }
974
+ /*
975
+ * Five types to be split:
976
+ * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
977
+ * <ins>A</ins>X<ins>C</ins><del>D</del>
978
+ * <ins>A</ins><del>B</del>X<ins>C</ins>
979
+ * <ins>A</del>X<ins>C</ins><del>D</del>
980
+ * <ins>A</ins><del>B</del>X<del>C</del>
981
+ */
982
+ if (lastequality && ((pre_ins && pre_del && post_ins && post_del) ||
983
+ ((lastequality.length < this.Diff_EditCost / 2) &&
984
+ (pre_ins + pre_del + post_ins + post_del) == 3))) {
985
+ // Duplicate record.
986
+ diffs.splice(equalities[equalitiesLength - 1], 0,
987
+ [DIFF_DELETE, lastequality]);
988
+ // Change second copy to insert.
989
+ diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
990
+ equalitiesLength--; // Throw away the equality we just deleted;
991
+ lastequality = '';
992
+ if (pre_ins && pre_del) {
993
+ // No changes made which could affect previous entry, keep going.
994
+ post_ins = post_del = true;
995
+ equalitiesLength = 0;
996
+ } else {
997
+ equalitiesLength--; // Throw away the previous equality.
998
+ pointer = equalitiesLength > 0 ?
999
+ equalities[equalitiesLength - 1] : -1;
1000
+ post_ins = post_del = false;
1001
+ }
1002
+ changes = true;
1003
+ }
1004
+ }
1005
+ pointer++;
1006
+ }
1007
+
1008
+ if (changes) {
1009
+ this.diff_cleanupMerge(diffs);
1010
+ }
1011
+ };
1012
+
1013
+
1014
+ /**
1015
+ * Reorder and merge like edit sections. Merge equalities.
1016
+ * Any edit section can move as long as it doesn't cross an equality.
1017
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1018
+ */
1019
+ diff_match_patch.prototype.diff_cleanupMerge = function(diffs) {
1020
+ diffs.push([DIFF_EQUAL, '']); // Add a dummy entry at the end.
1021
+ var pointer = 0;
1022
+ var count_delete = 0;
1023
+ var count_insert = 0;
1024
+ var text_delete = '';
1025
+ var text_insert = '';
1026
+ var commonlength;
1027
+ while (pointer < diffs.length) {
1028
+ switch (diffs[pointer][0]) {
1029
+ case DIFF_INSERT:
1030
+ count_insert++;
1031
+ text_insert += diffs[pointer][1];
1032
+ pointer++;
1033
+ break;
1034
+ case DIFF_DELETE:
1035
+ count_delete++;
1036
+ text_delete += diffs[pointer][1];
1037
+ pointer++;
1038
+ break;
1039
+ case DIFF_EQUAL:
1040
+ // Upon reaching an equality, check for prior redundancies.
1041
+ if (count_delete + count_insert > 1) {
1042
+ if (count_delete !== 0 && count_insert !== 0) {
1043
+ // Factor out any common prefixies.
1044
+ commonlength = this.diff_commonPrefix(text_insert, text_delete);
1045
+ if (commonlength !== 0) {
1046
+ if ((pointer - count_delete - count_insert) > 0 &&
1047
+ diffs[pointer - count_delete - count_insert - 1][0] ==
1048
+ DIFF_EQUAL) {
1049
+ diffs[pointer - count_delete - count_insert - 1][1] +=
1050
+ text_insert.substring(0, commonlength);
1051
+ } else {
1052
+ diffs.splice(0, 0, [DIFF_EQUAL,
1053
+ text_insert.substring(0, commonlength)]);
1054
+ pointer++;
1055
+ }
1056
+ text_insert = text_insert.substring(commonlength);
1057
+ text_delete = text_delete.substring(commonlength);
1058
+ }
1059
+ // Factor out any common suffixies.
1060
+ commonlength = this.diff_commonSuffix(text_insert, text_delete);
1061
+ if (commonlength !== 0) {
1062
+ diffs[pointer][1] = text_insert.substring(text_insert.length -
1063
+ commonlength) + diffs[pointer][1];
1064
+ text_insert = text_insert.substring(0, text_insert.length -
1065
+ commonlength);
1066
+ text_delete = text_delete.substring(0, text_delete.length -
1067
+ commonlength);
1068
+ }
1069
+ }
1070
+ // Delete the offending records and add the merged ones.
1071
+ if (count_delete === 0) {
1072
+ diffs.splice(pointer - count_delete - count_insert,
1073
+ count_delete + count_insert, [DIFF_INSERT, text_insert]);
1074
+ } else if (count_insert === 0) {
1075
+ diffs.splice(pointer - count_delete - count_insert,
1076
+ count_delete + count_insert, [DIFF_DELETE, text_delete]);
1077
+ } else {
1078
+ diffs.splice(pointer - count_delete - count_insert,
1079
+ count_delete + count_insert, [DIFF_DELETE, text_delete],
1080
+ [DIFF_INSERT, text_insert]);
1081
+ }
1082
+ pointer = pointer - count_delete - count_insert +
1083
+ (count_delete ? 1 : 0) + (count_insert ? 1 : 0) + 1;
1084
+ } else if (pointer !== 0 && diffs[pointer - 1][0] == DIFF_EQUAL) {
1085
+ // Merge this equality with the previous one.
1086
+ diffs[pointer - 1][1] += diffs[pointer][1];
1087
+ diffs.splice(pointer, 1);
1088
+ } else {
1089
+ pointer++;
1090
+ }
1091
+ count_insert = 0;
1092
+ count_delete = 0;
1093
+ text_delete = '';
1094
+ text_insert = '';
1095
+ break;
1096
+ }
1097
+ }
1098
+ if (diffs[diffs.length - 1][1] === '') {
1099
+ diffs.pop(); // Remove the dummy entry at the end.
1100
+ }
1101
+
1102
+ // Second pass: look for single edits surrounded on both sides by equalities
1103
+ // which can be shifted sideways to eliminate an equality.
1104
+ // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
1105
+ var changes = false;
1106
+ pointer = 1;
1107
+ // Intentionally ignore the first and last element (don't need checking).
1108
+ while (pointer < diffs.length - 1) {
1109
+ if (diffs[pointer - 1][0] == DIFF_EQUAL &&
1110
+ diffs[pointer + 1][0] == DIFF_EQUAL) {
1111
+ // This is a single edit surrounded by equalities.
1112
+ if (diffs[pointer][1].substring(diffs[pointer][1].length -
1113
+ diffs[pointer - 1][1].length) == diffs[pointer - 1][1]) {
1114
+ // Shift the edit over the previous equality.
1115
+ diffs[pointer][1] = diffs[pointer - 1][1] +
1116
+ diffs[pointer][1].substring(0, diffs[pointer][1].length -
1117
+ diffs[pointer - 1][1].length);
1118
+ diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
1119
+ diffs.splice(pointer - 1, 1);
1120
+ changes = true;
1121
+ } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) ==
1122
+ diffs[pointer + 1][1]) {
1123
+ // Shift the edit over the next equality.
1124
+ diffs[pointer - 1][1] += diffs[pointer + 1][1];
1125
+ diffs[pointer][1] =
1126
+ diffs[pointer][1].substring(diffs[pointer + 1][1].length) +
1127
+ diffs[pointer + 1][1];
1128
+ diffs.splice(pointer + 1, 1);
1129
+ changes = true;
1130
+ }
1131
+ }
1132
+ pointer++;
1133
+ }
1134
+ // If shifts were made, the diff needs reordering and another shift sweep.
1135
+ if (changes) {
1136
+ this.diff_cleanupMerge(diffs);
1137
+ }
1138
+ };
1139
+
1140
+
1141
+ /**
1142
+ * loc is a location in text1, compute and return the equivalent location in
1143
+ * text2.
1144
+ * e.g. 'The cat' vs 'The big cat', 1->1, 5->8
1145
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1146
+ * @param {number} loc Location within text1.
1147
+ * @return {number} Location within text2.
1148
+ */
1149
+ diff_match_patch.prototype.diff_xIndex = function(diffs, loc) {
1150
+ var chars1 = 0;
1151
+ var chars2 = 0;
1152
+ var last_chars1 = 0;
1153
+ var last_chars2 = 0;
1154
+ var x;
1155
+ for (x = 0; x < diffs.length; x++) {
1156
+ if (diffs[x][0] !== DIFF_INSERT) { // Equality or deletion.
1157
+ chars1 += diffs[x][1].length;
1158
+ }
1159
+ if (diffs[x][0] !== DIFF_DELETE) { // Equality or insertion.
1160
+ chars2 += diffs[x][1].length;
1161
+ }
1162
+ if (chars1 > loc) { // Overshot the location.
1163
+ break;
1164
+ }
1165
+ last_chars1 = chars1;
1166
+ last_chars2 = chars2;
1167
+ }
1168
+ // Was the location was deleted?
1169
+ if (diffs.length != x && diffs[x][0] === DIFF_DELETE) {
1170
+ return last_chars2;
1171
+ }
1172
+ // Add the remaining character length.
1173
+ return last_chars2 + (loc - last_chars1);
1174
+ };
1175
+
1176
+
1177
+ /**
1178
+ * Convert a diff array into a pretty HTML report.
1179
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1180
+ * @return {string} HTML representation.
1181
+ */
1182
+ diff_match_patch.prototype.diff_prettyHtml = function(diffs) {
1183
+ var html = [];
1184
+ var i = 0;
1185
+ var pattern_amp = /&/g;
1186
+ var pattern_lt = /</g;
1187
+ var pattern_gt = />/g;
1188
+ var pattern_para = /\n/g;
1189
+ for (var x = 0; x < diffs.length; x++) {
1190
+ var op = diffs[x][0]; // Operation (insert, delete, equal)
1191
+ var data = diffs[x][1]; // Text of change.
1192
+ var text = data.replace(pattern_amp, '&amp;').replace(pattern_lt, '&lt;')
1193
+ .replace(pattern_gt, '&gt;').replace(pattern_para, '<span class="para">&para;</span><br>');
1194
+ switch (op) {
1195
+ case DIFF_INSERT:
1196
+ html[x] = '<ins>' + text + '</ins>';
1197
+ break;
1198
+ case DIFF_DELETE:
1199
+ html[x] = '<del>' + text + '</del>';
1200
+ break;
1201
+ case DIFF_EQUAL:
1202
+ html[x] = '<span>' + text + '</span>';
1203
+ break;
1204
+ }
1205
+ if (op !== DIFF_DELETE) {
1206
+ i += data.length;
1207
+ }
1208
+ }
1209
+ return html.join('');
1210
+ };
1211
+
1212
+
1213
+ /**
1214
+ * Compute and return the source text (all equalities and deletions).
1215
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1216
+ * @return {string} Source text.
1217
+ */
1218
+ diff_match_patch.prototype.diff_text1 = function(diffs) {
1219
+ var text = [];
1220
+ for (var x = 0; x < diffs.length; x++) {
1221
+ if (diffs[x][0] !== DIFF_INSERT) {
1222
+ text[x] = diffs[x][1];
1223
+ }
1224
+ }
1225
+ return text.join('');
1226
+ };
1227
+
1228
+
1229
+ /**
1230
+ * Compute and return the destination text (all equalities and insertions).
1231
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1232
+ * @return {string} Destination text.
1233
+ */
1234
+ diff_match_patch.prototype.diff_text2 = function(diffs) {
1235
+ var text = [];
1236
+ for (var x = 0; x < diffs.length; x++) {
1237
+ if (diffs[x][0] !== DIFF_DELETE) {
1238
+ text[x] = diffs[x][1];
1239
+ }
1240
+ }
1241
+ return text.join('');
1242
+ };
1243
+
1244
+
1245
+ /**
1246
+ * Compute the Levenshtein distance; the number of inserted, deleted or
1247
+ * substituted characters.
1248
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1249
+ * @return {number} Number of changes.
1250
+ */
1251
+ diff_match_patch.prototype.diff_levenshtein = function(diffs) {
1252
+ var levenshtein = 0;
1253
+ var insertions = 0;
1254
+ var deletions = 0;
1255
+ for (var x = 0; x < diffs.length; x++) {
1256
+ var op = diffs[x][0];
1257
+ var data = diffs[x][1];
1258
+ switch (op) {
1259
+ case DIFF_INSERT:
1260
+ insertions += data.length;
1261
+ break;
1262
+ case DIFF_DELETE:
1263
+ deletions += data.length;
1264
+ break;
1265
+ case DIFF_EQUAL:
1266
+ // A deletion and an insertion is one substitution.
1267
+ levenshtein += Math.max(insertions, deletions);
1268
+ insertions = 0;
1269
+ deletions = 0;
1270
+ break;
1271
+ }
1272
+ }
1273
+ levenshtein += Math.max(insertions, deletions);
1274
+ return levenshtein;
1275
+ };
1276
+
1277
+
1278
+ /**
1279
+ * Crush the diff into an encoded string which describes the operations
1280
+ * required to transform text1 into text2.
1281
+ * E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'.
1282
+ * Operations are tab-separated. Inserted text is escaped using %xx notation.
1283
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
1284
+ * @return {string} Delta text.
1285
+ */
1286
+ diff_match_patch.prototype.diff_toDelta = function(diffs) {
1287
+ var text = [];
1288
+ for (var x = 0; x < diffs.length; x++) {
1289
+ switch (diffs[x][0]) {
1290
+ case DIFF_INSERT:
1291
+ text[x] = '+' + encodeURI(diffs[x][1]);
1292
+ break;
1293
+ case DIFF_DELETE:
1294
+ text[x] = '-' + diffs[x][1].length;
1295
+ break;
1296
+ case DIFF_EQUAL:
1297
+ text[x] = '=' + diffs[x][1].length;
1298
+ break;
1299
+ }
1300
+ }
1301
+ return text.join('\t').replace(/%20/g, ' ');
1302
+ };
1303
+
1304
+
1305
+ /**
1306
+ * Given the original text1, and an encoded string which describes the
1307
+ * operations required to transform text1 into text2, compute the full diff.
1308
+ * @param {string} text1 Source string for the diff.
1309
+ * @param {string} delta Delta text.
1310
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
1311
+ * @throws {!Error} If invalid input.
1312
+ */
1313
+ diff_match_patch.prototype.diff_fromDelta = function(text1, delta) {
1314
+ var diffs = [];
1315
+ var diffsLength = 0; // Keeping our own length var is faster in JS.
1316
+ var pointer = 0; // Cursor in text1
1317
+ var tokens = delta.split(/\t/g);
1318
+ for (var x = 0; x < tokens.length; x++) {
1319
+ // Each token begins with a one character parameter which specifies the
1320
+ // operation of this token (delete, insert, equality).
1321
+ var param = tokens[x].substring(1);
1322
+ switch (tokens[x].charAt(0)) {
1323
+ case '+':
1324
+ try {
1325
+ diffs[diffsLength++] = [DIFF_INSERT, decodeURI(param)];
1326
+ } catch (ex) {
1327
+ // Malformed URI sequence.
1328
+ throw new Error('Illegal escape in diff_fromDelta: ' + param);
1329
+ }
1330
+ break;
1331
+ case '-':
1332
+ // Fall through.
1333
+ case '=':
1334
+ var n = parseInt(param, 10);
1335
+ if (isNaN(n) || n < 0) {
1336
+ throw new Error('Invalid number in diff_fromDelta: ' + param);
1337
+ }
1338
+ var text = text1.substring(pointer, pointer += n);
1339
+ if (tokens[x].charAt(0) == '=') {
1340
+ diffs[diffsLength++] = [DIFF_EQUAL, text];
1341
+ } else {
1342
+ diffs[diffsLength++] = [DIFF_DELETE, text];
1343
+ }
1344
+ break;
1345
+ default:
1346
+ // Blank tokens are ok (from a trailing \t).
1347
+ // Anything else is an error.
1348
+ if (tokens[x]) {
1349
+ throw new Error('Invalid diff operation in diff_fromDelta: ' +
1350
+ tokens[x]);
1351
+ }
1352
+ }
1353
+ }
1354
+ if (pointer != text1.length) {
1355
+ throw new Error('Delta length (' + pointer +
1356
+ ') does not equal source text length (' + text1.length + ').');
1357
+ }
1358
+ return diffs;
1359
+ };
1360
+
1361
+
1362
+ // MATCH FUNCTIONS
1363
+
1364
+
1365
+ /**
1366
+ * Locate the best instance of 'pattern' in 'text' near 'loc'.
1367
+ * @param {string} text The text to search.
1368
+ * @param {string} pattern The pattern to search for.
1369
+ * @param {number} loc The location to search around.
1370
+ * @return {number} Best match index or -1.
1371
+ */
1372
+ diff_match_patch.prototype.match_main = function(text, pattern, loc) {
1373
+ // Check for null inputs.
1374
+ if (text == null || pattern == null || loc == null) {
1375
+ throw new Error('Null input. (match_main)');
1376
+ }
1377
+
1378
+ loc = Math.max(0, Math.min(loc, text.length));
1379
+ if (text == pattern) {
1380
+ // Shortcut (potentially not guaranteed by the algorithm)
1381
+ return 0;
1382
+ } else if (!text.length) {
1383
+ // Nothing to match.
1384
+ return -1;
1385
+ } else if (text.substring(loc, loc + pattern.length) == pattern) {
1386
+ // Perfect match at the perfect spot! (Includes case of null pattern)
1387
+ return loc;
1388
+ } else {
1389
+ // Do a fuzzy compare.
1390
+ return this.match_bitap_(text, pattern, loc);
1391
+ }
1392
+ };
1393
+
1394
+
1395
+ /**
1396
+ * Locate the best instance of 'pattern' in 'text' near 'loc' using the
1397
+ * Bitap algorithm.
1398
+ * @param {string} text The text to search.
1399
+ * @param {string} pattern The pattern to search for.
1400
+ * @param {number} loc The location to search around.
1401
+ * @return {number} Best match index or -1.
1402
+ * @private
1403
+ */
1404
+ diff_match_patch.prototype.match_bitap_ = function(text, pattern, loc) {
1405
+ if (pattern.length > this.Match_MaxBits) {
1406
+ throw new Error('Pattern too long for this browser.');
1407
+ }
1408
+
1409
+ // Initialise the alphabet.
1410
+ var s = this.match_alphabet_(pattern);
1411
+
1412
+ var dmp = this; // 'this' becomes 'window' in a closure.
1413
+
1414
+ /**
1415
+ * Compute and return the score for a match with e errors and x location.
1416
+ * Accesses loc and pattern through being a closure.
1417
+ * @param {number} e Number of errors in match.
1418
+ * @param {number} x Location of match.
1419
+ * @return {number} Overall score for match (0.0 = good, 1.0 = bad).
1420
+ * @private
1421
+ */
1422
+ function match_bitapScore_(e, x) {
1423
+ var accuracy = e / pattern.length;
1424
+ var proximity = Math.abs(loc - x);
1425
+ if (!dmp.Match_Distance) {
1426
+ // Dodge divide by zero error.
1427
+ return proximity ? 1.0 : accuracy;
1428
+ }
1429
+ return accuracy + (proximity / dmp.Match_Distance);
1430
+ }
1431
+
1432
+ // Highest score beyond which we give up.
1433
+ var score_threshold = this.Match_Threshold;
1434
+ // Is there a nearby exact match? (speedup)
1435
+ var best_loc = text.indexOf(pattern, loc);
1436
+ if (best_loc != -1) {
1437
+ score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold);
1438
+ // What about in the other direction? (speedup)
1439
+ best_loc = text.lastIndexOf(pattern, loc + pattern.length);
1440
+ if (best_loc != -1) {
1441
+ score_threshold =
1442
+ Math.min(match_bitapScore_(0, best_loc), score_threshold);
1443
+ }
1444
+ }
1445
+
1446
+ // Initialise the bit arrays.
1447
+ var matchmask = 1 << (pattern.length - 1);
1448
+ best_loc = -1;
1449
+
1450
+ var bin_min, bin_mid;
1451
+ var bin_max = pattern.length + text.length;
1452
+ var last_rd;
1453
+ for (var d = 0; d < pattern.length; d++) {
1454
+ // Scan for the best match; each iteration allows for one more error.
1455
+ // Run a binary search to determine how far from 'loc' we can stray at this
1456
+ // error level.
1457
+ bin_min = 0;
1458
+ bin_mid = bin_max;
1459
+ while (bin_min < bin_mid) {
1460
+ if (match_bitapScore_(d, loc + bin_mid) <= score_threshold) {
1461
+ bin_min = bin_mid;
1462
+ } else {
1463
+ bin_max = bin_mid;
1464
+ }
1465
+ bin_mid = Math.floor((bin_max - bin_min) / 2 + bin_min);
1466
+ }
1467
+ // Use the result from this iteration as the maximum for the next.
1468
+ bin_max = bin_mid;
1469
+ var start = Math.max(1, loc - bin_mid + 1);
1470
+ var finish = Math.min(loc + bin_mid, text.length) + pattern.length;
1471
+
1472
+ var rd = Array(finish + 2);
1473
+ rd[finish + 1] = (1 << d) - 1;
1474
+ for (var j = finish; j >= start; j--) {
1475
+ // The alphabet (s) is a sparse hash, so the following line generates
1476
+ // warnings.
1477
+ var charMatch = s[text.charAt(j - 1)];
1478
+ if (d === 0) { // First pass: exact match.
1479
+ rd[j] = ((rd[j + 1] << 1) | 1) & charMatch;
1480
+ } else { // Subsequent passes: fuzzy match.
1481
+ rd[j] = ((rd[j + 1] << 1) | 1) & charMatch |
1482
+ (((last_rd[j + 1] | last_rd[j]) << 1) | 1) |
1483
+ last_rd[j + 1];
1484
+ }
1485
+ if (rd[j] & matchmask) {
1486
+ var score = match_bitapScore_(d, j - 1);
1487
+ // This match will almost certainly be better than any existing match.
1488
+ // But check anyway.
1489
+ if (score <= score_threshold) {
1490
+ // Told you so.
1491
+ score_threshold = score;
1492
+ best_loc = j - 1;
1493
+ if (best_loc > loc) {
1494
+ // When passing loc, don't exceed our current distance from loc.
1495
+ start = Math.max(1, 2 * loc - best_loc);
1496
+ } else {
1497
+ // Already passed loc, downhill from here on in.
1498
+ break;
1499
+ }
1500
+ }
1501
+ }
1502
+ }
1503
+ // No hope for a (better) match at greater error levels.
1504
+ if (match_bitapScore_(d + 1, loc) > score_threshold) {
1505
+ break;
1506
+ }
1507
+ last_rd = rd;
1508
+ }
1509
+ return best_loc;
1510
+ };
1511
+
1512
+
1513
+ /**
1514
+ * Initialise the alphabet for the Bitap algorithm.
1515
+ * @param {string} pattern The text to encode.
1516
+ * @return {!Object} Hash of character locations.
1517
+ * @private
1518
+ */
1519
+ diff_match_patch.prototype.match_alphabet_ = function(pattern) {
1520
+ var s = {};
1521
+ for (var i = 0; i < pattern.length; i++) {
1522
+ s[pattern.charAt(i)] = 0;
1523
+ }
1524
+ for (var i = 0; i < pattern.length; i++) {
1525
+ s[pattern.charAt(i)] |= 1 << (pattern.length - i - 1);
1526
+ }
1527
+ return s;
1528
+ };
1529
+
1530
+
1531
+ // PATCH FUNCTIONS
1532
+
1533
+
1534
+ /**
1535
+ * Increase the context until it is unique,
1536
+ * but don't let the pattern expand beyond Match_MaxBits.
1537
+ * @param {!patch_obj} patch The patch to grow.
1538
+ * @param {string} text Source text.
1539
+ * @private
1540
+ */
1541
+ diff_match_patch.prototype.patch_addContext_ = function(patch, text) {
1542
+ if (text.length == 0) {
1543
+ return;
1544
+ }
1545
+ var pattern = text.substring(patch.start2, patch.start2 + patch.length1);
1546
+ var padding = 0;
1547
+
1548
+ // Look for the first and last matches of pattern in text. If two different
1549
+ // matches are found, increase the pattern length.
1550
+ while (text.indexOf(pattern) != text.lastIndexOf(pattern) &&
1551
+ pattern.length < this.Match_MaxBits - this.Patch_Margin -
1552
+ this.Patch_Margin) {
1553
+ padding += this.Patch_Margin;
1554
+ pattern = text.substring(patch.start2 - padding,
1555
+ patch.start2 + patch.length1 + padding);
1556
+ }
1557
+ // Add one chunk for good luck.
1558
+ padding += this.Patch_Margin;
1559
+
1560
+ // Add the prefix.
1561
+ var prefix = text.substring(patch.start2 - padding, patch.start2);
1562
+ if (prefix) {
1563
+ patch.diffs.unshift([DIFF_EQUAL, prefix]);
1564
+ }
1565
+ // Add the suffix.
1566
+ var suffix = text.substring(patch.start2 + patch.length1,
1567
+ patch.start2 + patch.length1 + padding);
1568
+ if (suffix) {
1569
+ patch.diffs.push([DIFF_EQUAL, suffix]);
1570
+ }
1571
+
1572
+ // Roll back the start points.
1573
+ patch.start1 -= prefix.length;
1574
+ patch.start2 -= prefix.length;
1575
+ // Extend the lengths.
1576
+ patch.length1 += prefix.length + suffix.length;
1577
+ patch.length2 += prefix.length + suffix.length;
1578
+ };
1579
+
1580
+
1581
+ /**
1582
+ * Compute a list of patches to turn text1 into text2.
1583
+ * Use diffs if provided, otherwise compute it ourselves.
1584
+ * There are four ways to call this function, depending on what data is
1585
+ * available to the caller:
1586
+ * Method 1:
1587
+ * a = text1, b = text2
1588
+ * Method 2:
1589
+ * a = diffs
1590
+ * Method 3 (optimal):
1591
+ * a = text1, b = diffs
1592
+ * Method 4 (deprecated, use method 3):
1593
+ * a = text1, b = text2, c = diffs
1594
+ *
1595
+ * @param {string|!Array.<!diff_match_patch.Diff>} a text1 (methods 1,3,4) or
1596
+ * Array of diff tuples for text1 to text2 (method 2).
1597
+ * @param {string|!Array.<!diff_match_patch.Diff>} opt_b text2 (methods 1,4) or
1598
+ * Array of diff tuples for text1 to text2 (method 3) or undefined (method 2).
1599
+ * @param {string|!Array.<!diff_match_patch.Diff>} opt_c Array of diff tuples
1600
+ * for text1 to text2 (method 4) or undefined (methods 1,2,3).
1601
+ * @return {!Array.<!patch_obj>} Array of patch objects.
1602
+ */
1603
+ diff_match_patch.prototype.patch_make = function(a, opt_b, opt_c) {
1604
+ var text1, diffs;
1605
+ if (typeof a == 'string' && typeof opt_b == 'string' &&
1606
+ typeof opt_c == 'undefined') {
1607
+ // Method 1: text1, text2
1608
+ // Compute diffs from text1 and text2.
1609
+ text1 = /** @type {string} */(a);
1610
+ diffs = this.diff_main(text1, /** @type {string} */(opt_b), true);
1611
+ if (diffs.length > 2) {
1612
+ this.diff_cleanupSemantic(diffs);
1613
+ this.diff_cleanupEfficiency(diffs);
1614
+ }
1615
+ } else if (a && typeof a == 'object' && typeof opt_b == 'undefined' &&
1616
+ typeof opt_c == 'undefined') {
1617
+ // Method 2: diffs
1618
+ // Compute text1 from diffs.
1619
+ diffs = /** @type {!Array.<!diff_match_patch.Diff>} */(a);
1620
+ text1 = this.diff_text1(diffs);
1621
+ } else if (typeof a == 'string' && opt_b && typeof opt_b == 'object' &&
1622
+ typeof opt_c == 'undefined') {
1623
+ // Method 3: text1, diffs
1624
+ text1 = /** @type {string} */(a);
1625
+ diffs = /** @type {!Array.<!diff_match_patch.Diff>} */(opt_b);
1626
+ } else if (typeof a == 'string' && typeof opt_b == 'string' &&
1627
+ opt_c && typeof opt_c == 'object') {
1628
+ // Method 4: text1, text2, diffs
1629
+ // text2 is not used.
1630
+ text1 = /** @type {string} */(a);
1631
+ diffs = /** @type {!Array.<!diff_match_patch.Diff>} */(opt_c);
1632
+ } else {
1633
+ throw new Error('Unknown call format to patch_make.');
1634
+ }
1635
+
1636
+ if (diffs.length === 0) {
1637
+ return []; // Get rid of the null case.
1638
+ }
1639
+ var patches = [];
1640
+ var patch = new patch_obj();
1641
+ var patchDiffLength = 0; // Keeping our own length var is faster in JS.
1642
+ var char_count1 = 0; // Number of characters into the text1 string.
1643
+ var char_count2 = 0; // Number of characters into the text2 string.
1644
+ // Start with text1 (prepatch_text) and apply the diffs until we arrive at
1645
+ // text2 (postpatch_text). We recreate the patches one by one to determine
1646
+ // context info.
1647
+ var prepatch_text = text1;
1648
+ var postpatch_text = text1;
1649
+ for (var x = 0; x < diffs.length; x++) {
1650
+ var diff_type = diffs[x][0];
1651
+ var diff_text = diffs[x][1];
1652
+
1653
+ if (!patchDiffLength && diff_type !== DIFF_EQUAL) {
1654
+ // A new patch starts here.
1655
+ patch.start1 = char_count1;
1656
+ patch.start2 = char_count2;
1657
+ }
1658
+
1659
+ switch (diff_type) {
1660
+ case DIFF_INSERT:
1661
+ patch.diffs[patchDiffLength++] = diffs[x];
1662
+ patch.length2 += diff_text.length;
1663
+ postpatch_text = postpatch_text.substring(0, char_count2) + diff_text +
1664
+ postpatch_text.substring(char_count2);
1665
+ break;
1666
+ case DIFF_DELETE:
1667
+ patch.length1 += diff_text.length;
1668
+ patch.diffs[patchDiffLength++] = diffs[x];
1669
+ postpatch_text = postpatch_text.substring(0, char_count2) +
1670
+ postpatch_text.substring(char_count2 +
1671
+ diff_text.length);
1672
+ break;
1673
+ case DIFF_EQUAL:
1674
+ if (diff_text.length <= 2 * this.Patch_Margin &&
1675
+ patchDiffLength && diffs.length != x + 1) {
1676
+ // Small equality inside a patch.
1677
+ patch.diffs[patchDiffLength++] = diffs[x];
1678
+ patch.length1 += diff_text.length;
1679
+ patch.length2 += diff_text.length;
1680
+ } else if (diff_text.length >= 2 * this.Patch_Margin) {
1681
+ // Time for a new patch.
1682
+ if (patchDiffLength) {
1683
+ this.patch_addContext_(patch, prepatch_text);
1684
+ patches.push(patch);
1685
+ patch = new patch_obj();
1686
+ patchDiffLength = 0;
1687
+ // Unlike Unidiff, our patch lists have a rolling context.
1688
+ // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff
1689
+ // Update prepatch text & pos to reflect the application of the
1690
+ // just completed patch.
1691
+ prepatch_text = postpatch_text;
1692
+ char_count1 = char_count2;
1693
+ }
1694
+ }
1695
+ break;
1696
+ }
1697
+
1698
+ // Update the current character count.
1699
+ if (diff_type !== DIFF_INSERT) {
1700
+ char_count1 += diff_text.length;
1701
+ }
1702
+ if (diff_type !== DIFF_DELETE) {
1703
+ char_count2 += diff_text.length;
1704
+ }
1705
+ }
1706
+ // Pick up the leftover patch if not empty.
1707
+ if (patchDiffLength) {
1708
+ this.patch_addContext_(patch, prepatch_text);
1709
+ patches.push(patch);
1710
+ }
1711
+
1712
+ return patches;
1713
+ };
1714
+
1715
+
1716
+ /**
1717
+ * Given an array of patches, return another array that is identical.
1718
+ * @param {!Array.<!patch_obj>} patches Array of patch objects.
1719
+ * @return {!Array.<!patch_obj>} Array of patch objects.
1720
+ */
1721
+ diff_match_patch.prototype.patch_deepCopy = function(patches) {
1722
+ // Making deep copies is hard in JavaScript.
1723
+ var patchesCopy = [];
1724
+ for (var x = 0; x < patches.length; x++) {
1725
+ var patch = patches[x];
1726
+ var patchCopy = new patch_obj();
1727
+ patchCopy.diffs = [];
1728
+ for (var y = 0; y < patch.diffs.length; y++) {
1729
+ patchCopy.diffs[y] = patch.diffs[y].slice();
1730
+ }
1731
+ patchCopy.start1 = patch.start1;
1732
+ patchCopy.start2 = patch.start2;
1733
+ patchCopy.length1 = patch.length1;
1734
+ patchCopy.length2 = patch.length2;
1735
+ patchesCopy[x] = patchCopy;
1736
+ }
1737
+ return patchesCopy;
1738
+ };
1739
+
1740
+
1741
+ /**
1742
+ * Merge a set of patches onto the text. Return a patched text, as well
1743
+ * as a list of true/false values indicating which patches were applied.
1744
+ * @param {!Array.<!patch_obj>} patches Array of patch objects.
1745
+ * @param {string} text Old text.
1746
+ * @return {!Array.<string|!Array.<boolean>>} Two element Array, containing the
1747
+ * new text and an array of boolean values.
1748
+ */
1749
+ diff_match_patch.prototype.patch_apply = function(patches, text) {
1750
+ if (patches.length == 0) {
1751
+ return [text, []];
1752
+ }
1753
+
1754
+ // Deep copy the patches so that no changes are made to originals.
1755
+ patches = this.patch_deepCopy(patches);
1756
+
1757
+ var nullPadding = this.patch_addPadding(patches);
1758
+ text = nullPadding + text + nullPadding;
1759
+
1760
+ this.patch_splitMax(patches);
1761
+ // delta keeps track of the offset between the expected and actual location
1762
+ // of the previous patch. If there are patches expected at positions 10 and
1763
+ // 20, but the first patch was found at 12, delta is 2 and the second patch
1764
+ // has an effective expected position of 22.
1765
+ var delta = 0;
1766
+ var results = [];
1767
+ for (var x = 0; x < patches.length; x++) {
1768
+ var expected_loc = patches[x].start2 + delta;
1769
+ var text1 = this.diff_text1(patches[x].diffs);
1770
+ var start_loc;
1771
+ var end_loc = -1;
1772
+ if (text1.length > this.Match_MaxBits) {
1773
+ // patch_splitMax will only provide an oversized pattern in the case of
1774
+ // a monster delete.
1775
+ start_loc = this.match_main(text, text1.substring(0, this.Match_MaxBits),
1776
+ expected_loc);
1777
+ if (start_loc != -1) {
1778
+ end_loc = this.match_main(text,
1779
+ text1.substring(text1.length - this.Match_MaxBits),
1780
+ expected_loc + text1.length - this.Match_MaxBits);
1781
+ if (end_loc == -1 || start_loc >= end_loc) {
1782
+ // Can't find valid trailing context. Drop this patch.
1783
+ start_loc = -1;
1784
+ }
1785
+ }
1786
+ } else {
1787
+ start_loc = this.match_main(text, text1, expected_loc);
1788
+ }
1789
+ if (start_loc == -1) {
1790
+ // No match found. :(
1791
+ results[x] = false;
1792
+ // Subtract the delta for this failed patch from subsequent patches.
1793
+ delta -= patches[x].length2 - patches[x].length1;
1794
+ } else {
1795
+ // Found a match. :)
1796
+ results[x] = true;
1797
+ delta = start_loc - expected_loc;
1798
+ var text2;
1799
+ if (end_loc == -1) {
1800
+ text2 = text.substring(start_loc, start_loc + text1.length);
1801
+ } else {
1802
+ text2 = text.substring(start_loc, end_loc + this.Match_MaxBits);
1803
+ }
1804
+ if (text1 == text2) {
1805
+ // Perfect match, just shove the replacement text in.
1806
+ text = text.substring(0, start_loc) +
1807
+ this.diff_text2(patches[x].diffs) +
1808
+ text.substring(start_loc + text1.length);
1809
+ } else {
1810
+ // Imperfect match. Run a diff to get a framework of equivalent
1811
+ // indices.
1812
+ var diffs = this.diff_main(text1, text2, false);
1813
+ if (text1.length > this.Match_MaxBits &&
1814
+ this.diff_levenshtein(diffs) / text1.length >
1815
+ this.Patch_DeleteThreshold) {
1816
+ // The end points match, but the content is unacceptably bad.
1817
+ results[x] = false;
1818
+ } else {
1819
+ this.diff_cleanupSemanticLossless(diffs);
1820
+ var index1 = 0;
1821
+ var index2;
1822
+ for (var y = 0; y < patches[x].diffs.length; y++) {
1823
+ var mod = patches[x].diffs[y];
1824
+ if (mod[0] !== DIFF_EQUAL) {
1825
+ index2 = this.diff_xIndex(diffs, index1);
1826
+ }
1827
+ if (mod[0] === DIFF_INSERT) { // Insertion
1828
+ text = text.substring(0, start_loc + index2) + mod[1] +
1829
+ text.substring(start_loc + index2);
1830
+ } else if (mod[0] === DIFF_DELETE) { // Deletion
1831
+ text = text.substring(0, start_loc + index2) +
1832
+ text.substring(start_loc + this.diff_xIndex(diffs,
1833
+ index1 + mod[1].length));
1834
+ }
1835
+ if (mod[0] !== DIFF_DELETE) {
1836
+ index1 += mod[1].length;
1837
+ }
1838
+ }
1839
+ }
1840
+ }
1841
+ }
1842
+ }
1843
+ // Strip the padding off.
1844
+ text = text.substring(nullPadding.length, text.length - nullPadding.length);
1845
+ return [text, results];
1846
+ };
1847
+
1848
+
1849
+ /**
1850
+ * Add some padding on text start and end so that edges can match something.
1851
+ * Intended to be called only from within patch_apply.
1852
+ * @param {!Array.<!patch_obj>} patches Array of patch objects.
1853
+ * @return {string} The padding string added to each side.
1854
+ */
1855
+ diff_match_patch.prototype.patch_addPadding = function(patches) {
1856
+ var paddingLength = this.Patch_Margin;
1857
+ var nullPadding = '';
1858
+ for (var x = 1; x <= paddingLength; x++) {
1859
+ nullPadding += String.fromCharCode(x);
1860
+ }
1861
+
1862
+ // Bump all the patches forward.
1863
+ for (var x = 0; x < patches.length; x++) {
1864
+ patches[x].start1 += paddingLength;
1865
+ patches[x].start2 += paddingLength;
1866
+ }
1867
+
1868
+ // Add some padding on start of first diff.
1869
+ var patch = patches[0];
1870
+ var diffs = patch.diffs;
1871
+ if (diffs.length == 0 || diffs[0][0] != DIFF_EQUAL) {
1872
+ // Add nullPadding equality.
1873
+ diffs.unshift([DIFF_EQUAL, nullPadding]);
1874
+ patch.start1 -= paddingLength; // Should be 0.
1875
+ patch.start2 -= paddingLength; // Should be 0.
1876
+ patch.length1 += paddingLength;
1877
+ patch.length2 += paddingLength;
1878
+ } else if (paddingLength > diffs[0][1].length) {
1879
+ // Grow first equality.
1880
+ var extraLength = paddingLength - diffs[0][1].length;
1881
+ diffs[0][1] = nullPadding.substring(diffs[0][1].length) + diffs[0][1];
1882
+ patch.start1 -= extraLength;
1883
+ patch.start2 -= extraLength;
1884
+ patch.length1 += extraLength;
1885
+ patch.length2 += extraLength;
1886
+ }
1887
+
1888
+ // Add some padding on end of last diff.
1889
+ patch = patches[patches.length - 1];
1890
+ diffs = patch.diffs;
1891
+ if (diffs.length == 0 || diffs[diffs.length - 1][0] != DIFF_EQUAL) {
1892
+ // Add nullPadding equality.
1893
+ diffs.push([DIFF_EQUAL, nullPadding]);
1894
+ patch.length1 += paddingLength;
1895
+ patch.length2 += paddingLength;
1896
+ } else if (paddingLength > diffs[diffs.length - 1][1].length) {
1897
+ // Grow last equality.
1898
+ var extraLength = paddingLength - diffs[diffs.length - 1][1].length;
1899
+ diffs[diffs.length - 1][1] += nullPadding.substring(0, extraLength);
1900
+ patch.length1 += extraLength;
1901
+ patch.length2 += extraLength;
1902
+ }
1903
+
1904
+ return nullPadding;
1905
+ };
1906
+
1907
+
1908
+ /**
1909
+ * Look through the patches and break up any which are longer than the maximum
1910
+ * limit of the match algorithm.
1911
+ * Intended to be called only from within patch_apply.
1912
+ * @param {!Array.<!patch_obj>} patches Array of patch objects.
1913
+ */
1914
+ diff_match_patch.prototype.patch_splitMax = function(patches) {
1915
+ var patch_size = this.Match_MaxBits;
1916
+ for (var x = 0; x < patches.length; x++) {
1917
+ if (patches[x].length1 > patch_size) {
1918
+ var bigpatch = patches[x];
1919
+ // Remove the big old patch.
1920
+ patches.splice(x--, 1);
1921
+ var start1 = bigpatch.start1;
1922
+ var start2 = bigpatch.start2;
1923
+ var precontext = '';
1924
+ while (bigpatch.diffs.length !== 0) {
1925
+ // Create one of several smaller patches.
1926
+ var patch = new patch_obj();
1927
+ var empty = true;
1928
+ patch.start1 = start1 - precontext.length;
1929
+ patch.start2 = start2 - precontext.length;
1930
+ if (precontext !== '') {
1931
+ patch.length1 = patch.length2 = precontext.length;
1932
+ patch.diffs.push([DIFF_EQUAL, precontext]);
1933
+ }
1934
+ while (bigpatch.diffs.length !== 0 &&
1935
+ patch.length1 < patch_size - this.Patch_Margin) {
1936
+ var diff_type = bigpatch.diffs[0][0];
1937
+ var diff_text = bigpatch.diffs[0][1];
1938
+ if (diff_type === DIFF_INSERT) {
1939
+ // Insertions are harmless.
1940
+ patch.length2 += diff_text.length;
1941
+ start2 += diff_text.length;
1942
+ patch.diffs.push(bigpatch.diffs.shift());
1943
+ empty = false;
1944
+ } else if (diff_type === DIFF_DELETE && patch.diffs.length == 1 &&
1945
+ patch.diffs[0][0] == DIFF_EQUAL &&
1946
+ diff_text.length > 2 * patch_size) {
1947
+ // This is a large deletion. Let it pass in one chunk.
1948
+ patch.length1 += diff_text.length;
1949
+ start1 += diff_text.length;
1950
+ empty = false;
1951
+ patch.diffs.push([diff_type, diff_text]);
1952
+ bigpatch.diffs.shift();
1953
+ } else {
1954
+ // Deletion or equality. Only take as much as we can stomach.
1955
+ diff_text = diff_text.substring(0,
1956
+ patch_size - patch.length1 - this.Patch_Margin);
1957
+ patch.length1 += diff_text.length;
1958
+ start1 += diff_text.length;
1959
+ if (diff_type === DIFF_EQUAL) {
1960
+ patch.length2 += diff_text.length;
1961
+ start2 += diff_text.length;
1962
+ } else {
1963
+ empty = false;
1964
+ }
1965
+ patch.diffs.push([diff_type, diff_text]);
1966
+ if (diff_text == bigpatch.diffs[0][1]) {
1967
+ bigpatch.diffs.shift();
1968
+ } else {
1969
+ bigpatch.diffs[0][1] =
1970
+ bigpatch.diffs[0][1].substring(diff_text.length);
1971
+ }
1972
+ }
1973
+ }
1974
+ // Compute the head context for the next patch.
1975
+ precontext = this.diff_text2(patch.diffs);
1976
+ precontext =
1977
+ precontext.substring(precontext.length - this.Patch_Margin);
1978
+ // Append the end context for this patch.
1979
+ var postcontext = this.diff_text1(bigpatch.diffs)
1980
+ .substring(0, this.Patch_Margin);
1981
+ if (postcontext !== '') {
1982
+ patch.length1 += postcontext.length;
1983
+ patch.length2 += postcontext.length;
1984
+ if (patch.diffs.length !== 0 &&
1985
+ patch.diffs[patch.diffs.length - 1][0] === DIFF_EQUAL) {
1986
+ patch.diffs[patch.diffs.length - 1][1] += postcontext;
1987
+ } else {
1988
+ patch.diffs.push([DIFF_EQUAL, postcontext]);
1989
+ }
1990
+ }
1991
+ if (!empty) {
1992
+ patches.splice(++x, 0, patch);
1993
+ }
1994
+ }
1995
+ }
1996
+ }
1997
+ };
1998
+
1999
+
2000
+ /**
2001
+ * Take a list of patches and return a textual representation.
2002
+ * @param {!Array.<!patch_obj>} patches Array of patch objects.
2003
+ * @return {string} Text representation of patches.
2004
+ */
2005
+ diff_match_patch.prototype.patch_toText = function(patches) {
2006
+ var text = [];
2007
+ for (var x = 0; x < patches.length; x++) {
2008
+ text[x] = patches[x];
2009
+ }
2010
+ return text.join('');
2011
+ };
2012
+
2013
+
2014
+ /**
2015
+ * Parse a textual representation of patches and return a list of patch objects.
2016
+ * @param {string} textline Text representation of patches.
2017
+ * @return {!Array.<!patch_obj>} Array of patch objects.
2018
+ * @throws {!Error} If invalid input.
2019
+ */
2020
+ diff_match_patch.prototype.patch_fromText = function(textline) {
2021
+ var patches = [];
2022
+ if (!textline) {
2023
+ return patches;
2024
+ }
2025
+ var text = textline.split('\n');
2026
+ var textPointer = 0;
2027
+ var patchHeader = /^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;
2028
+ while (textPointer < text.length) {
2029
+ var m = text[textPointer].match(patchHeader);
2030
+ if (!m) {
2031
+ throw new Error('Invalid patch string: ' + text[textPointer]);
2032
+ }
2033
+ var patch = new patch_obj();
2034
+ patches.push(patch);
2035
+ patch.start1 = parseInt(m[1], 10);
2036
+ if (m[2] === '') {
2037
+ patch.start1--;
2038
+ patch.length1 = 1;
2039
+ } else if (m[2] == '0') {
2040
+ patch.length1 = 0;
2041
+ } else {
2042
+ patch.start1--;
2043
+ patch.length1 = parseInt(m[2], 10);
2044
+ }
2045
+
2046
+ patch.start2 = parseInt(m[3], 10);
2047
+ if (m[4] === '') {
2048
+ patch.start2--;
2049
+ patch.length2 = 1;
2050
+ } else if (m[4] == '0') {
2051
+ patch.length2 = 0;
2052
+ } else {
2053
+ patch.start2--;
2054
+ patch.length2 = parseInt(m[4], 10);
2055
+ }
2056
+ textPointer++;
2057
+
2058
+ while (textPointer < text.length) {
2059
+ var sign = text[textPointer].charAt(0);
2060
+ try {
2061
+ var line = decodeURI(text[textPointer].substring(1));
2062
+ } catch (ex) {
2063
+ // Malformed URI sequence.
2064
+ throw new Error('Illegal escape in patch_fromText: ' + line);
2065
+ }
2066
+ if (sign == '-') {
2067
+ // Deletion.
2068
+ patch.diffs.push([DIFF_DELETE, line]);
2069
+ } else if (sign == '+') {
2070
+ // Insertion.
2071
+ patch.diffs.push([DIFF_INSERT, line]);
2072
+ } else if (sign == ' ') {
2073
+ // Minor equality.
2074
+ patch.diffs.push([DIFF_EQUAL, line]);
2075
+ } else if (sign == '@') {
2076
+ // Start of next patch.
2077
+ break;
2078
+ } else if (sign === '') {
2079
+ // Blank line? Whatever.
2080
+ } else {
2081
+ // WTF?
2082
+ throw new Error('Invalid patch mode "' + sign + '" in: ' + line);
2083
+ }
2084
+ textPointer++;
2085
+ }
2086
+ }
2087
+ return patches;
2088
+ };
2089
+
2090
+
2091
+ /**
2092
+ * Class representing one patch operation.
2093
+ * @constructor
2094
+ */
2095
+ function patch_obj() {
2096
+ /** @type {!Array.<!diff_match_patch.Diff>} */
2097
+ this.diffs = [];
2098
+ /** @type {?number} */
2099
+ this.start1 = null;
2100
+ /** @type {?number} */
2101
+ this.start2 = null;
2102
+ /** @type {number} */
2103
+ this.length1 = 0;
2104
+ /** @type {number} */
2105
+ this.length2 = 0;
2106
+ }
2107
+
2108
+
2109
+ /**
2110
+ * Emmulate GNU diff's format.
2111
+ * Header: @@ -382,8 +481,9 @@
2112
+ * Indicies are printed as 1-based, not 0-based.
2113
+ * @return {string} The GNU diff string.
2114
+ */
2115
+ patch_obj.prototype.toString = function() {
2116
+ var coords1, coords2;
2117
+ if (this.length1 === 0) {
2118
+ coords1 = this.start1 + ',0';
2119
+ } else if (this.length1 == 1) {
2120
+ coords1 = this.start1 + 1;
2121
+ } else {
2122
+ coords1 = (this.start1 + 1) + ',' + this.length1;
2123
+ }
2124
+ if (this.length2 === 0) {
2125
+ coords2 = this.start2 + ',0';
2126
+ } else if (this.length2 == 1) {
2127
+ coords2 = this.start2 + 1;
2128
+ } else {
2129
+ coords2 = (this.start2 + 1) + ',' + this.length2;
2130
+ }
2131
+ var text = ['@@ -' + coords1 + ' +' + coords2 + ' @@\n'];
2132
+ var op;
2133
+ // Escape the body of the patch with %xx notation.
2134
+ for (var x = 0; x < this.diffs.length; x++) {
2135
+ switch (this.diffs[x][0]) {
2136
+ case DIFF_INSERT:
2137
+ op = '+';
2138
+ break;
2139
+ case DIFF_DELETE:
2140
+ op = '-';
2141
+ break;
2142
+ case DIFF_EQUAL:
2143
+ op = ' ';
2144
+ break;
2145
+ }
2146
+ text[x + 1] = op + encodeURI(this.diffs[x][1]) + '\n';
2147
+ }
2148
+ return text.join('').replace(/%20/g, ' ');
2149
+ };
2150
+
2151
+ return diff_match_patch;
2152
+
2153
+ }());