coopy 0.6.4.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.md +22 -0
  7. data/README.md +59 -0
  8. data/Rakefile +4 -6
  9. data/coopy.gemspec +26 -0
  10. data/lib/coopy.rb +32 -175
  11. data/lib/coopy/alignment.rb +260 -0
  12. data/lib/coopy/bag.rb +17 -0
  13. data/lib/coopy/cell_info.rb +24 -0
  14. data/lib/coopy/change_type.rb +10 -0
  15. data/lib/coopy/compare_flags.rb +62 -0
  16. data/lib/coopy/compare_table.rb +327 -0
  17. data/lib/coopy/coopy.rb +22 -0
  18. data/lib/coopy/cross_match.rb +10 -0
  19. data/lib/coopy/csv_table.rb +51 -0
  20. data/lib/coopy/diff_render.rb +307 -0
  21. data/lib/coopy/index.rb +73 -0
  22. data/lib/coopy/index_item.rb +17 -0
  23. data/lib/coopy/index_pair.rb +72 -0
  24. data/lib/coopy/mover.rb +123 -0
  25. data/lib/coopy/ordering.rb +27 -0
  26. data/lib/coopy/row.rb +9 -0
  27. data/lib/coopy/simple_cell.rb +15 -0
  28. data/lib/coopy/simple_table.rb +144 -0
  29. data/lib/coopy/simple_view.rb +36 -0
  30. data/lib/coopy/table.rb +44 -0
  31. data/lib/coopy/table_comparison_state.rb +33 -0
  32. data/lib/coopy/table_diff.rb +634 -0
  33. data/lib/coopy/table_text.rb +14 -0
  34. data/lib/coopy/table_view.rb +31 -0
  35. data/lib/coopy/unit.rb +53 -0
  36. data/lib/coopy/version.rb +3 -0
  37. data/lib/coopy/view.rb +34 -0
  38. data/spec/fixtures/bridges.html +10 -0
  39. data/spec/fixtures/bridges_diff.csv +8 -0
  40. data/spec/fixtures/bridges_new.csv +9 -0
  41. data/spec/fixtures/bridges_old.csv +9 -0
  42. data/spec/fixtures/planetary_bodies.html +22 -0
  43. data/spec/fixtures/planetary_bodies_diff.csv +19 -0
  44. data/spec/fixtures/planetary_bodies_new.csv +20 -0
  45. data/spec/fixtures/planetary_bodies_old.csv +19 -0
  46. data/spec/fixtures/quote_me.csv +10 -0
  47. data/spec/fixtures/quote_me2.csv +11 -0
  48. data/spec/integration/table_diff_spec.rb +57 -0
  49. data/spec/libs/compare_flags_spec.rb +40 -0
  50. data/spec/libs/coopy_spec.rb +14 -0
  51. data/spec/libs/ordering_spec.rb +28 -0
  52. data/spec/libs/unit_spec.rb +31 -0
  53. data/spec/spec_helper.rb +29 -0
  54. metadata +153 -46
  55. data/bin/sqlite_diff +0 -4
  56. data/bin/sqlite_patch +0 -4
  57. data/bin/sqlite_rediff +0 -4
  58. data/lib/coopy/dbi_sql_wrapper.rb +0 -89
  59. data/lib/coopy/diff_apply_sql.rb +0 -35
  60. data/lib/coopy/diff_columns.rb +0 -33
  61. data/lib/coopy/diff_output.rb +0 -21
  62. data/lib/coopy/diff_output_action.rb +0 -34
  63. data/lib/coopy/diff_output_group.rb +0 -40
  64. data/lib/coopy/diff_output_raw.rb +0 -17
  65. data/lib/coopy/diff_output_stats.rb +0 -45
  66. data/lib/coopy/diff_output_table.rb +0 -49
  67. data/lib/coopy/diff_output_tdiff.rb +0 -48
  68. data/lib/coopy/diff_parser.rb +0 -92
  69. data/lib/coopy/diff_render_csv.rb +0 -29
  70. data/lib/coopy/diff_render_html.rb +0 -74
  71. data/lib/coopy/diff_render_log.rb +0 -52
  72. data/lib/coopy/row_change.rb +0 -25
  73. data/lib/coopy/scraperwiki_sql_wrapper.rb +0 -8
  74. data/lib/coopy/scraperwiki_utils.rb +0 -23
  75. data/lib/coopy/sequel_sql_wrapper.rb +0 -73
  76. data/lib/coopy/sql_compare.rb +0 -222
  77. data/lib/coopy/sql_wrapper.rb +0 -34
  78. data/lib/coopy/sqlite_sql_wrapper.rb +0 -143
  79. data/test/test_coopy.rb +0 -126
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7493ee11a18d6521e605f88a26b937ce6b096f15
4
+ data.tar.gz: a0410f887465a882377849fe96e55c1c70588708
5
+ SHA512:
6
+ metadata.gz: 37677ed77595308b7a205686c3048ba02051603ca8b6ce3c6ff1000f97e5c8522a243472cf01e5f8782273a9161fa81540d70f9fbe0f13b30179a6f35e7f16a1
7
+ data.tar.gz: 6806bd9e2ded7bedd32315c6764beac55338b7ae50b5c119609840504e87ebe52fbf45c4d956ba065749603148676204dba430d62f429f2eeb74ae76541c3c67
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1,7 @@
1
+ # Coopy for Ruby Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ * First working version!
6
+ * Basic support for two-way diffs of Ruby CSV objects
7
+ * HTML output
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ ruby '2.0.0'
4
+ #ruby-gemset=coopy
5
+
6
+ # Specify your gem's dependencies in coopy.gemspec
7
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 The Open Data Institute
2
+
3
+ # MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,59 @@
1
+ # Coopy for Ruby
2
+
3
+ [![Build Status](http://jenkins.theodi.org/job/coopy-ruby-master/badge/icon)](http://jenkins.theodi.org/job/coopy-ruby-master/)
4
+ [![Dependency Status](https://gemnasium.com/theodi/coopy-ruby.png)](https://gemnasium.com/theodi/coopy-ruby)
5
+ [![Code Climate](https://codeclimate.com/github/theodi/coopy-ruby.png)](https://codeclimate.com/github/theodi/coopy-ruby)
6
+
7
+ A pure Ruby port of Paul Fitzpatrick's [coopyhx](http://paulfitz.github.io/coopyhx) library for tabular diffs.
8
+
9
+ Not all the coopyhx code is ported or tested. There will be bugs. However, basic two-file CSV diff appears to be working. See 'Usage' section below for details.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'coopy'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install coopy
24
+
25
+ ## Usage
26
+
27
+ You can diff Ruby's built-in CSV objects, like so:
28
+
29
+ ```
30
+ old_table = Coopy::CsvTable.new(old_csv_object)
31
+ new_table = Coopy::CsvTable.new(new_csv_object)
32
+
33
+ alignment = Coopy.compare_tables(old_table,new_table).align
34
+ flags = Coopy::CompareFlags.new
35
+ highlighter = Coopy::TableDiff.new(alignment,flags)
36
+
37
+ diff_table = Coopy::SimpleTable.new(0,0)
38
+ highlighter.hilite diff_table
39
+ ```
40
+
41
+ You can inspect `diff_table` to see the changes.
42
+
43
+ You can also generate an HTML view of this diff like this:
44
+
45
+ ```
46
+ diff2html = Coopy::DiffRender.new
47
+ diff2html.render diff_table
48
+ html = diff2html.html
49
+ ```
50
+
51
+ There is plenty more in the original coopyhx, but this is all that's known working at the moment.
52
+
53
+ ## Contributing
54
+
55
+ 1. Fork it
56
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
57
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
58
+ 4. Push to the branch (`git push origin my-new-feature`)
59
+ 5. Create new Pull Request
data/Rakefile CHANGED
@@ -1,8 +1,6 @@
1
- require 'rake/testtask'
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
2
3
 
3
- Rake::TestTask.new do |t|
4
- t.libs << 'test'
5
- end
4
+ RSpec::Core::RakeTask.new(:spec)
6
5
 
7
- desc "Run tests"
8
- task :default => :test
6
+ task :default => :spec
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'coopy/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "coopy"
8
+ spec.version = Coopy::VERSION
9
+ spec.authors = ["James Smith"]
10
+ spec.email = ["james@floppy.org.uk"]
11
+ spec.description = %q{Ruby port of coopyhx, for calculating tabular diffs}
12
+ spec.summary = %q{Ruby port of coopyhx, for calculating tabular diffs}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "simplecov-rcov"
25
+ spec.add_development_dependency "pry"
26
+ end
@@ -1,178 +1,35 @@
1
- require 'optparse'
1
+ require "coopy/version"
2
2
 
3
- class Coopy
4
-
5
- class Flavor
6
- attr_accessor :key
7
- attr_accessor :banner
8
- attr_accessor :min_length
9
-
10
- def sql_subject?
11
- [:diff,:patch].include? key
12
- end
13
-
14
- def sql_object?
15
- key == :diff
16
- end
17
-
18
- def can_choose_format?
19
- key != :patch
20
- end
21
-
22
- def can_set_output?
23
- key != :patch
24
- end
25
-
26
- def default_format
27
- (key==:patch) ? :apply : :csv
28
- end
29
- end
30
-
31
- class OpenStruct
32
- attr_accessor :format
33
- attr_accessor :output
34
- end
35
-
36
- def self.parse(flavor,args)
37
- options = OpenStruct.new
38
- options.format = flavor.default_format
39
- options.output = nil
40
- OptionParser.new do |opts|
41
- begin
42
- opts.banner = flavor.banner
43
- opts.separator ""
44
- opts.separator "Specific options"
45
- if flavor.can_choose_format?
46
- opts.on("-f","--format [FORMAT]", [:csv, :html, :tdiff, :apply, :stats],
47
- "select format (csv,html,tdiff,apply,stats)") do |fmt|
48
- options.format = fmt
49
- end
50
- end
51
- if flavor.can_set_output?
52
- opts.on("-o", "--output [FILENAME]",
53
- "direct output to a file") do |fname|
54
- options.output = fname
55
- end
56
- end
57
- opts.on_tail("-h", "--help", "Show this message") do
58
- puts opts
59
- exit
60
- end
61
- opts.parse!(args)
62
- return options
63
- rescue
64
- puts "#{$!} (--help for help)"
65
- exit 1
66
- end
67
- end
68
- end
69
-
70
- def self.core(flavor,argv)
71
- options = self.parse(flavor,argv)
72
-
73
- if argv.length < flavor.min_length
74
- self.parse(flavor,["--help"])
75
- exit(1)
76
- end
77
-
78
- if flavor.sql_subject?
79
- db = SQLite3::Database.new(argv[0])
80
- sql = SqliteSqlWrapper.new(db)
81
- end
82
-
83
- if flavor.sql_object?
84
- name1 = nil
85
- name2 = nil
86
- case argv.length
87
- when 2
88
- name0 = sql.get_table_names[0]
89
- db.execute("ATTACH ? AS `__peer_ - _`",argv[1])
90
- name1 = "main.#{name0}"
91
- name2 = "__peer_ - _.#{name0}"
92
- when 3
93
- name1 = argv[1]
94
- name2 = argv[2]
95
- when 4
96
- name1 = "main.#{argv[1]}"
97
- db.execute("ATTACH ? AS __peer__",argv[2])
98
- name2 = "__peer__.#{argv[3]}"
99
- end
100
- cmp = SqlCompare.new(sql,name1,name2)
101
- else
102
- cmp = DiffParser.new(argv[flavor.min_length-1])
103
- end
104
-
105
- patches = DiffOutputGroup.new
106
- # patches << DiffOutputRaw.new
107
- case options.format
108
- when :html
109
- patches << DiffRenderHtml.new
110
- when :tdiff
111
- patches << DiffOutputTdiff.new
112
- when :csv
113
- patches << DiffRenderCsv.new
114
- when :apply
115
- patches << DiffApplySql.new(sql,name1)
116
- when :raw
117
- patches << DiffOutputRaw.new
118
- when :stats
119
- patches << DiffOutputStats.new
120
- else
121
- patches << DiffRenderCsv.new
122
- end
123
-
124
- cmp.set_output(patches)
125
-
126
- cmp.apply
127
- result = patches.to_string
128
- if result != ""
129
- if options.output.nil?
130
- print result
131
- else
132
- File.open(options.output,"w") do |f|
133
- f << result
134
- end
135
- end
136
- end
137
- 0
138
- end
139
-
140
- def self.diff(argv)
141
- flavor = Flavor.new
142
- flavor.key = :diff
143
- flavor.banner = "Usage: sqlite_diff [options] ver1.sqlite ver2.sqlite"
144
- flavor.min_length = 2
145
- self.core(flavor,argv)
146
- end
147
-
148
- def self.patch(argv)
149
- flavor = Flavor.new
150
- flavor.key = :patch
151
- flavor.banner = "Usage: sqlite_patch [options] db.sqlite patch.csv"
152
- flavor.min_length = 2
153
- self.core(flavor,argv)
154
- end
155
-
156
- def self.rediff(argv)
157
- flavor = Flavor.new
158
- flavor.key = :rediff
159
- flavor.banner = "Usage: sqlite_rediff [options] patch.csv"
160
- flavor.min_length = 1
161
- self.core(flavor,argv)
162
- end
3
+ module Coopy
4
+ # Your code goes here...
163
5
  end
164
6
 
165
- require 'coopy/diff_output_raw'
166
- require 'coopy/diff_output_tdiff'
167
- require 'coopy/diff_render_html'
168
- require 'coopy/diff_render_csv'
169
- require 'coopy/diff_output_action'
170
- require 'coopy/diff_output_group'
171
- require 'coopy/diff_output_stats'
172
- require 'coopy/diff_apply_sql'
173
- require 'coopy/diff_parser'
174
-
175
- require 'coopy/sqlite_sql_wrapper'
176
- require 'coopy/sql_compare'
177
- require 'sqlite3'
178
-
7
+ # interfaces
8
+ require 'coopy/bag'
9
+ require 'coopy/row'
10
+ require 'coopy/table'
11
+ require 'coopy/view'
12
+
13
+ # proper classes
14
+ require 'coopy/compare_flags'
15
+ require 'coopy/change_type'
16
+ require 'coopy/cell_info'
17
+ require 'coopy/unit'
18
+ require 'coopy/ordering'
19
+ require 'coopy/simple_cell'
20
+ require 'coopy/index_item'
21
+ require 'coopy/index'
22
+ require 'coopy/cross_match'
23
+ require 'coopy/index_pair'
24
+ require 'coopy/alignment'
25
+ require 'coopy/table_view'
26
+ require 'coopy/table_comparison_state'
27
+ require 'coopy/compare_table'
28
+ require 'coopy/mover'
29
+ require 'coopy/table_diff'
30
+ require 'coopy/coopy'
31
+ require 'coopy/simple_view'
32
+ require 'coopy/csv_table'
33
+ require 'coopy/simple_table'
34
+ require 'coopy/table_text'
35
+ require 'coopy/diff_render'
@@ -0,0 +1,260 @@
1
+ module Coopy
2
+ class Alignment
3
+
4
+ attr_accessor :reference # Alignment
5
+ attr_accessor :meta # Alignment
6
+
7
+ def initialize
8
+ @map_a2b = {} # Map<Int,Int>
9
+ @map_b2a = {} # Map<Int,Int>
10
+ @ha = @hb = 0
11
+ @map_count = 0
12
+ @reference = nil
13
+ @meta = nil
14
+ @order_cache_has_reference = false
15
+ @ia = 0
16
+ @ib = 0
17
+ end
18
+
19
+ def range(ha, hb)
20
+ @ha = ha
21
+ @hb = hb
22
+ end
23
+
24
+ def tables(ta, tb)
25
+ @ta = ta
26
+ @tb = tb
27
+ end
28
+
29
+ def headers(ia, ib)
30
+ @ia = ia
31
+ @ib = ib
32
+ end
33
+
34
+ def set_rowlike(flag)
35
+ end
36
+
37
+ def hb
38
+ @hb
39
+ end
40
+
41
+ def link(a, b)
42
+ @map_a2b[a] = b
43
+ @map_b2a[b] = a
44
+ @map_count+=1
45
+ end
46
+
47
+ def add_index_columns(unit)
48
+ if @index_columns.nil?
49
+ @index_columns = []
50
+ end
51
+ @index_columns << unit
52
+ end
53
+
54
+ def get_index_columns
55
+ @index_columns
56
+ end
57
+
58
+ def a2b(a)
59
+ @map_a2b[a]
60
+ end
61
+
62
+ def b2a(b)
63
+ @map_b2a[b]
64
+ end
65
+
66
+ def count
67
+ @map_count
68
+ end
69
+
70
+ def to_s
71
+ map_a2b.to_s
72
+ end
73
+
74
+ def to_order
75
+ if @order_cache
76
+ if @reference
77
+ if !@order_cache_has_reference
78
+ @order_cache = nil
79
+ end
80
+ end
81
+ end
82
+ @order_cache = to_order_3 if @order_cache.nil?
83
+ @order_cache_has_reference = true if reference
84
+ @order_cache
85
+ end
86
+
87
+ def get_source
88
+ @ta
89
+ end
90
+
91
+ def get_target
92
+ @tb
93
+ end
94
+
95
+ def get_source_header
96
+ @ia
97
+ end
98
+
99
+ def get_target_header
100
+ @ib
101
+ end
102
+
103
+ def to_order_3
104
+ ref = @reference
105
+ if ref.nil?
106
+ ref = Coopy::Alignment.new
107
+ ref.range(@ha,@ha)
108
+ ref.tables(@ta,@ta)
109
+ (0...@ha).each do |i|
110
+ ref.link(i,i)
111
+ end
112
+ end
113
+ order = Coopy::Ordering.new
114
+ if @reference.nil?
115
+ order.ignore_parent
116
+ end
117
+ xp = 0
118
+ xl = 0
119
+ xr = 0
120
+ hp = @ha
121
+ hl = ref.hb
122
+ hr = @hb
123
+ vp = {}
124
+ vl = {}
125
+ vr = {}
126
+ (0...hp).each { |i| vp[i] = i }
127
+ (0...hl).each { |i| vl[i] = i }
128
+ (0...hr).each { |i| vr[i] = i }
129
+ ct_vp = hp
130
+ ct_vl = hl
131
+ ct_vr = hr
132
+ prev = -1
133
+ ct = 0
134
+ max_ct = (hp+hl+hr)*10
135
+ while (ct_vp>0 ||
136
+ ct_vl>0 ||
137
+ ct_vr>0) do
138
+ ct+=1
139
+ if ct>max_ct
140
+ puts("Ordering took too long, something went wrong")
141
+ break
142
+ end
143
+ xp = 0 if (xp>=hp)
144
+ xl = 0 if (xl>=hl)
145
+ xr = 0 if (xr>=hr)
146
+ if xp<hp && ct_vp>0
147
+ if a2b(xp).nil? && ref.a2b(xp).nil?
148
+ if vp.has_key?(xp)
149
+ order.add(-1,-1,xp)
150
+ prev = xp
151
+ vp.remove(xp)
152
+ ct_vp-=1
153
+ end
154
+ xp+=1
155
+ next
156
+ end
157
+ end
158
+ zl = nil
159
+ zr = nil
160
+ if xl<hl && ct_vl>0
161
+ zl = ref.b2a(xl)
162
+ if zl.nil?
163
+ if vl.has_key?(xl)
164
+ order.add(xl,-1,-1)
165
+ vl.remove(xl)
166
+ ct_vl-=1
167
+ end
168
+ xl+=1
169
+ next
170
+ end
171
+ end
172
+ if xr<hr && ct_vr>0
173
+ zr = b2a(xr)
174
+ if zr.nil?
175
+ if vr.has_key?(xr)
176
+ order.add(-1,xr,-1)
177
+ vr.delete(xr)
178
+ ct_vr-=1
179
+ end
180
+ xr+=1
181
+ next
182
+ end
183
+ end
184
+ if zl
185
+ if a2b(zl).nil?
186
+ # row deleted in remote
187
+ if vl.has_key?(xl)
188
+ order.add(xl,-1,zl)
189
+ prev = zl
190
+ vp.delete(zl)
191
+ ct_vp-=1
192
+ vl.delete(xl)
193
+ ct_vl-=1
194
+ xp = zl+1
195
+ end
196
+ xl+=1
197
+ next
198
+ end
199
+ end
200
+ if zr
201
+ if ref.a2b(zr).nil?
202
+ # row deleted in local
203
+ if vr.has_key?(xr)
204
+ order.add(-1,xr,zr)
205
+ prev = zr
206
+ vp.remove(zr)
207
+ ct_vp-=1
208
+ vr.remove(xr)
209
+ ct_vr-=1
210
+ xp = zr+1
211
+ end
212
+ xr+=1
213
+ next
214
+ end
215
+ end
216
+ if zl && zr && a2b(zl) && ref.a2b(zr)
217
+ # we have a choice of order
218
+ # local thinks zl should come next
219
+ # remote thinks zr should come next
220
+ if zl==prev+1 || zr!=prev+1
221
+ if vr.has_key?(xr)
222
+ order.add(ref.a2b(zr),xr,zr)
223
+ prev = zr
224
+ vp.delete(zr)
225
+ ct_vp-=1
226
+ vl.delete(ref.a2b(zr))
227
+ ct_vl-=1
228
+ vr.delete(xr)
229
+ ct_vr-=1
230
+ xp = zr+1
231
+ xl = ref.a2b(zr)+1
232
+ end
233
+ xr+=1
234
+ next
235
+ else
236
+ if vl.has_key?(xl)
237
+ order.add(xl,a2b(zl),zl)
238
+ prev = zl
239
+ vp.remove(zl)
240
+ ct_vp-=1
241
+ vl.remove(xl)
242
+ ct_vl-=1
243
+ vr.remove(a2b(zl))
244
+ ct_vr-=1
245
+ xp = zl+1
246
+ xr = a2b(zl)+1
247
+ end
248
+ xl+=1
249
+ next
250
+ end
251
+ end
252
+ xp+=1
253
+ xl+=1
254
+ xr+=1
255
+ end
256
+ return order
257
+ end
258
+
259
+ end
260
+ end