pagy 43.6.2 → 43.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3c2ddfcddfcd9d3b6f239dedcaea1a9a9e2fc90b649514f590731f4c273b289
4
- data.tar.gz: 03526b97bfecfcc087ab5ed74df946a833528949e3695f99d911bf74c1ad63d6
3
+ metadata.gz: acefb70fcb49a67bc580acb08d9d199cc57caecf51721e437cc475051641c555
4
+ data.tar.gz: 6a3bacb516190cd2669ea92c233338043bbe597d674ac0c4ed41799be9be1e2b
5
5
  SHA512:
6
- metadata.gz: b6c667dceaf46a8681e4cffe54bfc3a9b913990f9b5bcd462ff02c65c9f5e3d8b3106a2aed9614acaccdea0de203fca11308bc241891610f63ec3e22b059e074
7
- data.tar.gz: 581756adb642ccd061486404c056d01d5250cde5cf745d4c0e3bd651b31fe202cf49e376d816feb4f6c1dcfd5f2bdd7dc9d868187763f1aff52de7310f0114e8
6
+ metadata.gz: 4bbb2f141e1657e4c6edbb96ba4bf6668c2f449b894f8c1ef5b4ee689f6edd018a71134f0485674bad8276e52dd00ac156bece5e918caa07905bd6db94889d9d
7
+ data.tar.gz: 4d67fb4c5a20e3935734cc63851eee75d2a49d2b1280ed7c5f8874df90429e711c7fe0c605c372b9963639f5dde0711a54ccd2e3ef5706c8123b77fc09a85b75
@@ -0,0 +1,283 @@
1
+ # frozen_string_literal: true
2
+
3
+ # DESCRIPTION
4
+ # Showcase the ActiveSearch pagination (active and passive modes)
5
+ #
6
+ # DOC
7
+ # https://ddnexus.github.io/pagy/sandbox/playground/#active-search
8
+ #
9
+ # BIN HELP
10
+ # pagy -h
11
+ #
12
+ # DEV USAGE
13
+ # pagy clone active_search
14
+ # pagy ./active_search.ru
15
+ #
16
+ # URL
17
+ # http://127.0.0.1:8000
18
+
19
+ VERSION = '43.7.0'
20
+
21
+ if VERSION != Pagy::VERSION
22
+ Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
23
+ end
24
+
25
+ # Bundle
26
+ require 'bundler/inline'
27
+ gemfile(!Pagy::ROOT.join('pagy.gemspec').exist?) do
28
+ source 'https://rubygems.org'
29
+ gem 'oj'
30
+ gem 'puma'
31
+ gem 'rails', '~> 8.1'
32
+ gem 'sqlite3'
33
+ gem 'rails-active_search'
34
+ end
35
+
36
+ # require 'rails/all' # too much stuff
37
+ require 'action_controller/railtie'
38
+ require 'active_record'
39
+ require 'rails-active_search'
40
+
41
+ OUTPUT = Rails.env.showcase? ? IO::NULL : $stdout
42
+
43
+ # Rails config
44
+ class PagyActiveSearch < Rails::Application # :nodoc:
45
+ config.root = __dir__
46
+ config.eager_load = false
47
+ config.session_store :cookie_store, key: 'cookie_store_key'
48
+ Rails.application.credentials.secret_key_base = 'absolute_secret'
49
+
50
+ config.logger = Logger.new(OUTPUT)
51
+ Rails.logger = config.logger
52
+ end
53
+
54
+ # Initialize the app in order to run the ActiveSearch engine initializers
55
+ PagyActiveSearch.initialize!
56
+
57
+ # Draw the routes after the initialization, which would otherwise reset them
58
+ PagyActiveSearch.routes.draw do
59
+ root to: 'comments#active'
60
+ get '/comments/active', to: 'comments#active'
61
+ get '/comments/passive', to: 'comments#passive'
62
+ get '/javascripts/:file', to: 'pagy#javascripts', file: /.*/
63
+ end
64
+
65
+ # ActiveSearch reads its stores only from config/search.yml, so we apply the equivalent config directly.
66
+ # The sqlite adapter uses the ActiveRecord connection, so it takes no connection options.
67
+ ActiveSearch.configuration.apply_store_config(adapter: :sqlite)
68
+
69
+ # Activerecord initializer
70
+ ActiveRecord::Base.logger = Logger.new(OUTPUT)
71
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'file:memdb1?mode=memory&cache=shared')
72
+ ActiveRecord::Schema.define do
73
+ create_table :posts, force: true do |t|
74
+ t.string :title
75
+ end
76
+
77
+ create_table :comments, force: true do |t|
78
+ t.string :body
79
+ t.integer :post_id
80
+ end
81
+
82
+ # ActiveSearch sqlite documents: a table for the filterable fields and an FTS5 table for the text fields
83
+ create_table :post_documents, force: true do |t|
84
+ t.string :post_id, null: false, index: { unique: true }
85
+ end
86
+ create_virtual_table :post_documents_fts, :fts5, [:title]
87
+
88
+ create_table :comment_documents, force: true do |t|
89
+ t.string :comment_id, null: false, index: { unique: true }
90
+ t.integer :post_id
91
+ end
92
+ create_virtual_table :comment_documents_fts, :fts5, [:body]
93
+ end
94
+
95
+ class ApplicationRecord < ActiveRecord::Base
96
+ primary_abstract_class
97
+ end
98
+
99
+ # ActiveSearch document models (one per index)
100
+ class PostDocument < ApplicationRecord; end
101
+ class CommentDocument < ApplicationRecord; end
102
+
103
+ # Models
104
+ class Post < ApplicationRecord # :nodoc:
105
+ extend Pagy::Search
106
+
107
+ has_many :comments
108
+ has_search async: false
109
+ end
110
+
111
+ # :nodoc:
112
+
113
+ class Comment < ApplicationRecord # :nodoc:
114
+ extend Pagy::Search
115
+
116
+ belongs_to :post
117
+ has_search async: false
118
+ end
119
+
120
+ ActiveSearch.define_index(:posts) do
121
+ text :title
122
+ end
123
+
124
+ ActiveSearch.define_index(:comments) do
125
+ text :body
126
+ integer :post_id
127
+ end
128
+
129
+ # :nodoc:
130
+
131
+ # Unused model, useful to test overriding conflicts
132
+ module Calendar
133
+ end
134
+
135
+ # DB seed
136
+ 1.upto(11) do |pi|
137
+ Post.create(title: "Post #{pi + 1}")
138
+ end
139
+ Post.all.each_with_index do |post, pi|
140
+ 2.times { |ci| Comment.create(post:, body: "Comment #{ci + 1} to Post #{pi + 1}") }
141
+ end
142
+
143
+ # Controllers
144
+ class CommentsController < ActionController::Base # :nodoc:
145
+ include Rails.application.routes.url_helpers
146
+ include Pagy::Method
147
+
148
+ def active
149
+ search = Comment.pagy_search(params[:q])
150
+ @pagy, @comments = pagy(:rails_active_search, search, limit: 10, client_limit: 100)
151
+ # Reload the page in the network tab of the Chrome Inspector to check
152
+ # response.headers.merge!(@pagy.headers_hash)
153
+ render inline: TEMPLATE
154
+ end
155
+
156
+ def passive
157
+ limit = [params[:limit].to_i, 10].max.clamp(..100)
158
+ page = [params[:page].to_i, 1].max
159
+ @comments = Comment.search(params[:q]).limit(limit).offset(limit * (page - 1)).results
160
+ @pagy = pagy(:rails_active_search, @comments, client_limit: 100)
161
+ # Reload the page in the network tab of the Chrome Inspector to check
162
+ # response.headers.merge!(@pagy.headers_hash)
163
+ render inline: TEMPLATE
164
+ end
165
+ end
166
+
167
+ # You don't need this in real rails apps (see https://ddnexus.github.io/pagy/resources/javascripts)
168
+ class PagyController < ActionController::Base
169
+ def javascripts
170
+ format = params[:file].split('.').last
171
+ if format == 'js'
172
+ render js: Pagy::ROOT.join('javascripts', params[:file]).read
173
+ elsif format == 'map'
174
+ render json: Pagy::ROOT.join('javascripts', params[:file]).read
175
+ end
176
+ end
177
+ end
178
+
179
+ run PagyActiveSearch
180
+
181
+ TEMPLATE = <<~ERB
182
+ <!DOCTYPE html>
183
+ <html lang="en">
184
+ <head>
185
+ <title>Pagy ActiveSearch App</title>
186
+ <script src="/javascripts/pagy.js"></script>
187
+ <script>
188
+ window.addEventListener("load", Pagy.init);
189
+ </script>
190
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
191
+ <style type="text/css">
192
+ @media screen { html, body {
193
+ font-size: 1rem;
194
+ line-height: 1.2;
195
+ padding: 0;
196
+ margin: 0;
197
+ } }
198
+ body {
199
+ background: white !important;
200
+ margin: 0 !important;
201
+ font-family: sans-serif !important;
202
+ }
203
+ .main-content {
204
+ padding: 1rem 1.5rem 2rem !important;
205
+ }
206
+ .pagy, .pagy-bootstrap, .pagy-bulma {
207
+ padding: .5em;
208
+ margin: .3em 0;
209
+ width: fit-content;
210
+ box-shadow: 5px 5px 10px 0px rgba(0,0,0,0.2);
211
+ }
212
+
213
+ /* Quick demo for overriding the element style attribute of certain pagy helpers
214
+ .pagy input[style] {
215
+ width: 5rem !important;
216
+ }
217
+ */
218
+
219
+ /*
220
+ If you want to customize the style,
221
+ please replace the line below with the actual file content
222
+ */
223
+ <%== Pagy::ROOT.join('stylesheets/pagy.css').read %>
224
+ </style>
225
+ </head>
226
+
227
+ <body>
228
+
229
+ <div class="main-content">
230
+ <h1>Pagy ActiveSearch App</h1>
231
+ <p> Self-contained, standalone Rails app usable to easily reproduce any rails related pagy issue.</p>
232
+
233
+ <h2>Versions</h2>
234
+ <ul>
235
+ <li>Ruby: <%== RUBY_VERSION %></li>
236
+ <li>Rack: <%== Rack::RELEASE %></li>
237
+ <li>Rails: <%== Rails.version %></li>
238
+ <li>Pagy: <%== Pagy::VERSION %></li>
239
+ </ul>
240
+
241
+ <h3>Active Collection</h3>
242
+ <%= form_with url: { controller: 'comments', action: 'active' }, method: :get, local: true do |form| %>
243
+ <%= form.text_field :q, value: params[:q], placeholder: "Search..." %>
244
+ <%= form.submit "Search" %>
245
+ <% end %>
246
+
247
+ <h3>Passive Collection</h3>
248
+ <%= form_with url: { controller: 'comments', action: 'passive' }, method: :get, local: true do |form| %>
249
+ <%= form.text_field :q, value: params[:q], placeholder: "Search..." %>
250
+ <%= form.submit "Search" %>
251
+ <% end %>
252
+
253
+
254
+ <div id="records" class="collection">
255
+ <% @comments.each do |comment| %>
256
+ <p style="margin: 0;"><%= comment.body %></p>
257
+ <% end %>
258
+ </div>
259
+
260
+ <hr>
261
+
262
+ <h4>@pagy.series_nav</h4>
263
+ <%== @pagy.series_nav(id: 'series-nav',
264
+ aria_label: 'Pages nav') %>
265
+
266
+ <h4>@pagy.series_nav_js</h4>
267
+ <%== @pagy.series_nav_js(id: 'series-nav-js',
268
+ aria_label: 'Pages nav_js') %>
269
+
270
+ <h4>@pagy.input_nav_js</h4>
271
+ <%== @pagy.input_nav_js(id: 'input-nav-js',
272
+ aria_label: 'Pages input_nav_js') %>
273
+
274
+ <h4>@pagy.limit_tag_js</h4>
275
+ <%== @pagy.limit_tag_js(id: 'limit-tag-js') %>
276
+
277
+ <h4>@pagy.info_tag</h4>
278
+ <%== @pagy.info_tag(id: 'pagy-info') %>
279
+ </div>
280
+
281
+ </body>
282
+ </html>
283
+ ERB
data/apps/calendar.ru CHANGED
@@ -4,7 +4,7 @@
4
4
  # Showcase the calendar; reproduce related issues
5
5
  #
6
6
  # DOC
7
- # https://ddnexus.github.io/pagy/playground/#5-calendar-app
7
+ # https://ddnexus.github.io/pagy/sandbox/playground/#calendar
8
8
  #
9
9
  # BIN HELP
10
10
  # pagy -h
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.6.2'
19
+ VERSION = '43.7.0'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
@@ -46,6 +46,10 @@ require 'sinatra/base'
46
46
  class PagyCalendar < Sinatra::Base
47
47
  include Pagy::Method
48
48
 
49
+ # Serve one request at a time: concurrent requests calling the groupdate SQLite function
50
+ # on the shared in-memory database deadlock the server
51
+ use Rack::Lock
52
+
49
53
  if ENV['E2E_TEST']
50
54
  get('/assets/:file') do
51
55
  content_type 'text/css'
data/apps/demo.ru CHANGED
@@ -4,7 +4,7 @@
4
4
  # Showcase all the helpers and styles
5
5
  #
6
6
  # DOC
7
- # https://ddnexus.github.io/pagy/playground/#demo-app
7
+ # https://ddnexus.github.io/pagy/sandbox/playground/#demo
8
8
  #
9
9
  # BIN HELP
10
10
  # pagy -h
@@ -19,7 +19,7 @@
19
19
  # URL
20
20
  # http://127.0.0.1:8000
21
21
 
22
- VERSION = '43.6.2'
22
+ VERSION = '43.7.0'
23
23
 
24
24
  if VERSION != Pagy::VERSION
25
25
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
@@ -46,7 +46,7 @@ SECTIONS = { pagy: { css_anchor: 'pagy-css' },
46
46
  require 'sinatra/base'
47
47
 
48
48
  # Pagy init
49
- Pagy::OPTIONS[:max_limit] = 100
49
+ Pagy::OPTIONS[:client_limit] = 100
50
50
 
51
51
  # Sinatra application
52
52
  class PagyDemo < Sinatra::Base
@@ -47,7 +47,7 @@ class Pagy
47
47
  # Compose the final URL using `url_for`.
48
48
  module LinkableOverride
49
49
  def compose_url(absolute, _path, params, fragment)
50
- params[:anchor] = fragment if fragment
50
+ params[:anchor] = fragment unless fragment.to_s.empty?
51
51
  params[:only_path] = !absolute
52
52
  @context.url_for(params)
53
53
  end
@@ -4,19 +4,19 @@
4
4
  # Showcase the Keynav pagination with independent instances
5
5
  #
6
6
  # DOC
7
- # https://ddnexus.github.io/pagy/playground/#keyset-apps
7
+ # https://ddnexus.github.io/pagy/sandbox/playground/#keysets
8
8
  #
9
9
  # BIN HELP
10
10
  # pagy -h
11
11
  #
12
12
  # DEV USAGE
13
- # pagy clone keynav
14
- # pagy ./keynav.ru
13
+ # pagy clone keynav+root_key
14
+ # pagy ./keynav+root_key.ru
15
15
  #
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.6.2'
19
+ VERSION = '43.7.0'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
@@ -35,7 +35,7 @@ end
35
35
  # Sinatra setup
36
36
  require 'sinatra/base'
37
37
  # Sinatra application
38
- class PagyKeynav < Sinatra::Base
38
+ class PagyKeynavRootKey < Sinatra::Base
39
39
  include Pagy::Method
40
40
 
41
41
  get('/javascripts/:file') do
@@ -132,7 +132,7 @@ class PagyKeynav < Sinatra::Base
132
132
  template :main do
133
133
  <<~ERB
134
134
  <div class="main-content">
135
- <h1>Pagy Keynav App</h1>
135
+ <h1>Pagy Keynav (root_key) App</h1>
136
136
  <p>Self-contained, standalone app usable to easily reproduce any Keynav related pagy issue
137
137
  with ActiveRecord sets.</p>
138
138
  <p>The panels below show how to use the <code>:root_key</code> option for independent instances in the same request.</p>
@@ -313,4 +313,4 @@ data.each_line(chomp: true) do |pet|
313
313
  end
314
314
  Pet.insert_all(pets)
315
315
 
316
- run PagyKeynav
316
+ run PagyKeynavRootKey
data/apps/keynav.ru CHANGED
@@ -4,7 +4,7 @@
4
4
  # Showcase the Keynav pagination (ActiveRecord example)
5
5
  #
6
6
  # DOC
7
- # https://ddnexus.github.io/pagy/playground/#keyset-apps
7
+ # https://ddnexus.github.io/pagy/sandbox/playground/#keysets
8
8
  #
9
9
  # BIN HELP
10
10
  # pagy -h
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.6.2'
19
+ VERSION = '43.7.0'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
@@ -53,9 +53,9 @@ class PagyKeynav < Sinatra::Base
53
53
  Time.zone = 'UTC'
54
54
 
55
55
  @order = { animal: :asc, name: :asc, birthdate: :desc, id: :asc }.freeze
56
- @pagy, @pets = pagy(:keynav_js, Pet.order(@order), limit: 4, max_limit: 100)
56
+ @pagy, @pets = pagy(:keynav_js, Pet.order(@order), limit: 4, client_limit: 100)
57
57
  # Support also root_key for replacing url in javascript
58
- # @pagy, @pets = pagy(:keynav_js, Pet.order(@order), limit: 4, max_limit: 100, root_key: 'animal')
58
+ # @pagy, @pets = pagy(:keynav_js, Pet.order(@order), limit: 4, client_limit: 100, root_key: 'animal')
59
59
  @ids = @pets.pluck(:id)
60
60
  erb :main
61
61
  end
data/apps/keyset.ru CHANGED
@@ -4,7 +4,7 @@
4
4
  # Showcase the Keyset pagination (ActiveRecord example)
5
5
  #
6
6
  # DOC
7
- # https://ddnexus.github.io/pagy/playground/#keyset-apps
7
+ # https://ddnexus.github.io/pagy/sandbox/playground/#keysets
8
8
  #
9
9
  # BIN HELP
10
10
  # pagy -h
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.6.2'
19
+ VERSION = '43.7.0'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
@@ -43,10 +43,10 @@ class PagyKeyset < Sinatra::Base
43
43
  Time.zone = 'UTC'
44
44
 
45
45
  @order = { animal: :asc, name: :asc, birthdate: :desc, id: :asc }.freeze
46
- @pagy, @pets = pagy(:keyset, Pet.order(@order), limit: 10, max_limit: 100)
46
+ @pagy, @pets = pagy(:keyset, Pet.order(@order), limit: 10, client_limit: 100)
47
47
  # @pagy, @pets = pagy(:keyset, Pet.order(@order),
48
48
  # jsonapi: true, page_key: 'number', limit_key: 'size', # very customized jsonapi
49
- # limit: 10, max_limit: 100)
49
+ # limit: 10, client_limit: 100)
50
50
  # response.headers.merge!(@pagy.headers_hash)
51
51
  erb :main
52
52
  end
@@ -4,7 +4,7 @@
4
4
  # Showcase the Keyset pagination (Sequel example)
5
5
  #
6
6
  # DOC
7
- # https://ddnexus.github.io/pagy/playground/#keyset-apps
7
+ # https://ddnexus.github.io/pagy/sandbox/playground/#keysets
8
8
  #
9
9
  # BIN HELP
10
10
  # pagy -h
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.6.2'
19
+ VERSION = '43.7.0'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
@@ -43,7 +43,7 @@ class PagyKeysetSequel < Sinatra::Base
43
43
  get '/' do
44
44
  @order = { animal: :asc, name: :asc, birthdate: :desc, id: :asc }.freeze
45
45
  @pagy, @pets = pagy(:keyset, Pet.order(:animal, :name, Sequel.desc(:birthdate), :id),
46
- limit: 10, max_limit: 100)
46
+ limit: 10, client_limit: 100)
47
47
  erb :main
48
48
  end
49
49
 
data/apps/rails.ru CHANGED
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # DESCRIPTION
4
- # Reproduce rails related issues
4
+ # Reproduce Rails-related issues
5
5
  #
6
6
  # DOC
7
- # https://ddnexus.github.io/pagy/playground/#rails-app
7
+ # https://ddnexus.github.io/pagy/sandbox/playground/#rails
8
8
  #
9
9
  # BIN HELP
10
10
  # pagy -h
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.6.2'
19
+ VERSION = '43.7.0'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
@@ -28,7 +28,7 @@ gemfile(!Pagy::ROOT.join('pagy.gemspec').exist?) do
28
28
  source 'https://rubygems.org'
29
29
  gem 'oj'
30
30
  gem 'puma'
31
- gem 'rails', '~> 8.0'
31
+ gem 'rails', '~> 8.1'
32
32
  gem 'sqlite3'
33
33
  end
34
34
 
@@ -102,7 +102,7 @@ class CommentsController < ActionController::Base # :nodoc:
102
102
  include Pagy::Method
103
103
 
104
104
  def index
105
- @pagy, @comments = pagy(:offset, Comment.all, limit: 10, max_limit: 100)
105
+ @pagy, @comments = pagy(:offset, Comment.all, limit: 10, client_limit: 100)
106
106
  # Reload the page in the network tab of the Chrome Inspector to check
107
107
  # response.headers.merge!(@pagy.headers_hash)
108
108
  render inline: TEMPLATE
data/apps/repro.ru CHANGED
@@ -4,7 +4,7 @@
4
4
  # Reproduce generic/simple issues
5
5
  #
6
6
  # DOC
7
- # https://ddnexus.github.io/pagy/playground/#repro-app
7
+ # https://ddnexus.github.io/pagy/sandbox/playground/#repro
8
8
  #
9
9
  # BIN HELP
10
10
  # pagy -h
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.6.2'
19
+ VERSION = '43.7.0'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
@@ -34,7 +34,7 @@ end
34
34
 
35
35
  # Edit this section adding the legacy as needed
36
36
  # Pagy initializer
37
- Pagy::OPTIONS[:max_limit] = 100
37
+ Pagy::OPTIONS[:client_limit] = 100
38
38
 
39
39
  # Sinatra setup
40
40
  require 'sinatra/base'
@@ -56,7 +56,7 @@ class PagyRepro < Sinatra::Base
56
56
  get '/' do
57
57
  collection = MockCollection.new
58
58
  @pagy, @records = pagy(collection) # simplest form
59
- # @pagy, @records = pagy(:offset, collection, limit: 7, max_limit: 30)
59
+ # @pagy, @records = pagy(:offset, collection, limit: 7, client_limit: 30)
60
60
  # @pagy, @records = pagy(:countish, collection, ttl: 20)
61
61
  # @pagy, @records = pagy(:countless, collection)
62
62
  # @pagy, @records = pagy(Array(1..1000))
data/config/pagy.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Pagy initializer file (43.6.2)
3
+ # Pagy initializer file (43.7.0)
4
4
  # See https://ddnexus.github.io/pagy/toolbox/configuration/initializer/
5
5
 
6
6
 
@@ -9,7 +9,7 @@
9
9
  # Examples:
10
10
  #
11
11
  # Pagy::OPTIONS[:limit] = 10 # Limit the items per page
12
- # Pagy::OPTIONS[:max_limit] = 100 # The client is allowed to request a limit up to 100
12
+ # Pagy::OPTIONS[:client_limit] = 100 # The client is allowed to request a limit up to 100
13
13
  # Pagy::OPTIONS[:jsonapi] = true # Use JSON:API compliant URLs
14
14
 
15
15
  Pagy::OPTIONS.freeze
data/javascripts/pagy.js CHANGED
@@ -135,7 +135,7 @@ var pagy_default = (() => {
135
135
  });
136
136
  };
137
137
  return {
138
- version: "43.6.2",
138
+ version: "43.7.0",
139
139
  init(arg) {
140
140
  const target = arg instanceof HTMLElement ? arg : document, elements = target.querySelectorAll("[data-pagy]");
141
141
  for (const element of elements) {
@@ -162,5 +162,5 @@ var pagy_default = (() => {
162
162
  // pagy-shim.ts
163
163
  window.Pagy = pagy_default;
164
164
 
165
- //# debugId=142524AA8BD9779264756E2164756E21
166
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsicGFneS50cyIsICJwYWd5LXNoaW0udHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbCiAgICAiaW50ZXJmYWNlIFN5bmNEYXRhIHtcbiAgZnJvbT86IG51bWJlclxuICB0bz8gIDogbnVtYmVyXG4gIGtleSAgOiBzdHJpbmdcbiAgc3RyPyA6IHN0cmluZ1xufVxudHlwZSBJbml0QXJncyA9IFtcImtcIiwgIEtleW5hdkFyZ3NdIHwgICAgICAgICAgLy8gc2VyaWVzX25hdltfanNdIHdpdGgga2V5bmF2IGluc3RhbmNlXG4gICAgICAgICAgICAgICAgW1wic25qXCIsIFNlcmllc05hdkpzQXJnc10gfCAgICAvLyBzZXJpZXNfbmF2X2pzXG4gICAgICAgICAgICAgICAgW1wiaW5qXCIsIElucHV0TmF2SnNBcmdzXSB8ICAgICAvLyBpbnB1dF9uYXZfanNcbiAgICAgICAgICAgICAgICBbXCJsdGpcIiwgTGltaXRUYWdKc0FyZ3NdOyAgICAgIC8vIGxpbWl0X3RhZ19qc1xudHlwZSBBdWdtZW50S2V5bmF2ID0gKG5hdjpIVE1MRWxlbWVudCwga2V5bmF2QXJnczpLZXluYXZBcmdzKSA9PiBQcm9taXNlPCgocGFnZTogc3RyaW5nKSA9PiBzdHJpbmcpPjtcbnR5cGUgS2V5bmF2QXJncyA9IHJlYWRvbmx5IFtzdG9yYWdlS2V5IDogc3RyaW5nIHwgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb290S2V5ICAgIDogc3RyaW5nIHwgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlS2V5ICAgIDogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3QgICAgICAgOiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BsaWNlQXJncz86IFNwbGljZUFyZ3NdO1xudHlwZSBTcGxpY2VBcmdzID0gcmVhZG9ubHkgW3N0YXJ0ICAgICAgOiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlQ291bnQ6IG51bWJlciwgICAgIC8vIGl0IHdvdWxkIGJlIG9wdGlvbmFsLCBidXQgdHMgY29tcGxhaW5zXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uaXRlbXM6ICAgIEN1dG9mZltdXTtcbnR5cGUgQ3V0b2ZmID0gcmVhZG9ubHkgKHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4pW107XG50eXBlIEF1Z21lbnRlZFBhZ2UgPSBbYnJvd3NlcklkICA6IHN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgICBzdG9yYWdlS2V5IDogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgIHBhZ2VOdW1iZXIgOiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgcGFnZXMgICAgICA6IG51bWJlcixcbiAgICAgICAgICAgICAgICAgICAgICBwcmlvckN1dG9mZjogQ3V0b2ZmIHwgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICBwYWdlQ3V0b2ZmIDogQ3V0b2ZmIHwgbnVsbF07XG50eXBlIFNlcmllc05hdkpzQXJncyA9IHJlYWRvbmx5IFtOYXZKc1Rva2VucywgcGFnZVRva2VuOiBzdHJpbmcsIE5hdkpzU2VyaWVzLCBLZXluYXZBcmdzP107XG50eXBlIE5hdkpzU2VyaWVzID0gcmVhZG9ubHkgW3dpZHRoczogbnVtYmVyW10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllczogKHN0cmluZyB8IG51bWJlcilbXVtdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM6IHN0cmluZ1tdW10gfCBudWxsXTtcbnR5cGUgSW5wdXROYXZKc0FyZ3MgPSByZWFkb25seSBbdXJsVG9rZW46ICBzdHJpbmcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VUb2tlbjogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBLZXluYXZBcmdzP107XG50eXBlIExpbWl0VGFnSnNBcmdzID0gcmVhZG9ubHkgW2Zyb20gICAgICA6IG51bWJlcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXJsVG9rZW4gIDogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlVG9rZW4gOiBzdHJpbmcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0VG9rZW46IHN0cmluZ107XG50eXBlIE5hdkpzVG9rZW5zID0gcmVhZG9ubHkgW2JlZm9yZSA6IHN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5jaG9yIDogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50OiBzdHJpbmcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdhcCAgICA6IHN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWZ0ZXIgIDogc3RyaW5nXTtcbmludGVyZmFjZSBOYXZKc0VsZW1lbnQgZXh0ZW5kcyBIVE1MRWxlbWVudCB7XG4gIHJlbmRlcigpOiB2b2lkXG59XG5cbi8vIFRoZSBzeW50YXggdXNlZCBpbiB0aGlzIGZpbGUgaGFzIGJlZW4gY2FyZWZ1bGx5IGNvbXBvc2VkIHRvIG1pbmltaXplXG4vLyB0aGUgcGFneS5taW4uanMgc2l6ZSBhbmQgYXZvaWQgcG9sbHV0aW9uIGluIHRoZSB3aW5kb3cgb2JqZWN0LlxuZXhwb3J0IGRlZmF1bHQgKCgpID0+IHtcbiAgY29uc3Qgc3RvcmFnZVN1cHBvcnQgPSAnc2Vzc2lvblN0b3JhZ2UnIGluIHdpbmRvdyAmJiAnQnJvYWRjYXN0Q2hhbm5lbCcgaW4gd2luZG93O1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcHJlZmVyLWNvbnN0XG4gIGxldCBwYWd5ID0gXCJwYWd5XCIsIHN0b3JhZ2U6IFN0b3JhZ2UsIHN5bmM6IEJyb2FkY2FzdENoYW5uZWwsIHRhYklkOiBudW1iZXI7XG4gIGlmIChzdG9yYWdlU3VwcG9ydCkge1xuICAgIHN0b3JhZ2UgPSBzZXNzaW9uU3RvcmFnZTsgLy8gc2hvcnRlbiB0aGUgY29tcGlsZWQgc2l6ZVxuICAgIHN5bmMgICAgPSBuZXcgQnJvYWRjYXN0Q2hhbm5lbChwYWd5KTtcbiAgICB0YWJJZCAgID0gRGF0ZS5ub3coKTtcblxuICAgIC8vIFN5bmMgdGhlIHNlc3Npb25TdG9yYWdlIGtleXMgZm9yIHRoZSBjdXRvZmZzIG9wZW5lZCBpbiBhIG5ldyB0YWIvd2luZG93XG4gICAgc3luYy5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCAoZTpNZXNzYWdlRXZlbnQ8U3luY0RhdGE+KSA9PiB7XG4gICAgICBpZiAoZS5kYXRhLmZyb20pIHsgLy8gcmVxdWVzdCBjdXRvZmZzXG4gICAgICAgIGNvbnN0IGN1dG9mZnMgPSBzdG9yYWdlLmdldEl0ZW0oZS5kYXRhLmtleSk7XG4gICAgICAgIGlmIChjdXRvZmZzKSB7XG4gICAgICAgICAgc3luYy5wb3N0TWVzc2FnZSg8U3luY0RhdGE+e3RvOiBlLmRhdGEuZnJvbSwga2V5OiBlLmRhdGEua2V5LCBzdHI6IGN1dG9mZnN9KTtcbiAgICAgICAgfSAvLyBzZW5kIHJlc3BvbnNlXG4gICAgICB9IGVsc2UgaWYgKGUuZGF0YS50bykgeyAgLy8gcmVjZWl2ZSBjdXRvZmZzXG4gICAgICAgIGlmIChlLmRhdGEudG8gPT0gdGFiSWQpIHtcbiAgICAgICAgICBzdG9yYWdlLnNldEl0ZW0oZS5kYXRhLmtleSwgPHN0cmluZz5lLmRhdGEuc3RyKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9XG4gIC8vIFRoZSBvYnNlcnZlciBpbnN0YW5jZSBmb3IgcmVzcG9uc2l2ZSBuYXZzXG4gIGNvbnN0IHJqc09ic2VydmVyID0gbmV3IFJlc2l6ZU9ic2VydmVyKGVudHJpZXMgPT4ge1xuICAgIGVudHJpZXMuZm9yRWFjaChlID0+IHtcbiAgICAgIGUudGFyZ2V0LnF1ZXJ5U2VsZWN0b3JBbGw8TmF2SnNFbGVtZW50PihcIi5zZXJpZXMtbmF2LWpzXCIpLmZvckVhY2goZWwgPT4ge1xuICAgICAgICBlbC5yZW5kZXIoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICAvKiBGdWxsIHNldCBvZiBCNjQgZnVuY3Rpb25zXG4gIGNvbnN0IEI2NEVuY29kZSAgICAgPSAodW5pY29kZTpzdHJpbmcpID0+IGJ0b2EoU3RyaW5nLmZyb21DaGFyQ29kZSguLi4obmV3IFRleHRFbmNvZGVyKS5lbmNvZGUodW5pY29kZSkpKSxcbiAgICAgICAgQjY0U2FmZSAgICAgICA9ICh1bnNhZmU6c3RyaW5nKSAgPT4gdW5zYWZlLnJlcGxhY2UoL1srLz1dL2csIChtKSA9PiBtID09IFwiK1wiID8gXCItXCIgOiBtID09IFwiL1wiID8gXCJfXCIgOiBcIlwiKSxcbiAgICAgICAgQjY0U2FmZUVuY29kZSA9ICh1bmljb2RlOnN0cmluZykgPT4gQjY0U2FmZShCNjRFbmNvZGUodW5pY29kZSkpLFxuICAgICAgICBCNjREZWNvZGUgICAgID0gKGJhc2U2NDpzdHJpbmcpICA9PiAobmV3IFRleHREZWNvZGVyKCkpLmRlY29kZShVaW50OEFycmF5LmZyb20oYXRvYihiYXNlNjQpLCBjID0+IGMuY2hhckNvZGVBdCgwKSkpLFxuICAgICAgICBCNjRVbnNhZmUgICAgID0gKHNhZmU6c3RyaW5nKSAgICA9PiBzYWZlLnJlcGxhY2UoL1stX10vZywgKG1hdGNoKSA9PiBtYXRjaCA9PSBcIi1cIiA/IFwiK1wiIDogXCIvXCIpLFxuICAgICAgICBCNjRTYWZlRGVjb2RlID0gKGJhc2U2NDpzdHJpbmcpICA9PiBCNjREZWNvZGUoQjY0VW5zYWZlKGJhc2U2NCkpXG4gICovXG4gIGNvbnN0IEI2NFNhZmVFbmNvZGUgPSAodW5pY29kZTpzdHJpbmcpID0+IGJ0b2EoU3RyaW5nLmZyb21DaGFyQ29kZSguLi4obmV3IFRleHRFbmNvZGVyKS5lbmNvZGUodW5pY29kZSkpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoL1srLz1dL2csIChtKSA9PiBtID09IFwiK1wiID8gXCItXCIgOiBtID09IFwiL1wiID8gXCJfXCIgOiBcIlwiKSxcbiAgICAgICAgQjY0RGVjb2RlICAgICA9IChiYXNlNjQ6c3RyaW5nKSAgPT4gKG5ldyBUZXh0RGVjb2RlcigpKS5kZWNvZGUoVWludDhBcnJheS5mcm9tKGF0b2IoYmFzZTY0KSwgYyA9PiBjLmNoYXJDb2RlQXQoMCkpKTtcblxuICAvLyBSZXR1cm4gYSByYW5kb20ga2V5OiAzIGNoYXJzIG1heCwgYmFzZS0zNiBudW1iZXIgPCAzNioqM1xuICBjb25zdCByYW5kS2V5ID0gKCkgPT4gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMzYgKiogMykudG9TdHJpbmcoMzYpO1xuXG4gIC8vIE1hbmFnZSB0aGUgcGFnZSBhdWdtZW50YXRpb24gZm9yIEtleW5hdiwgY2FsbGVkIG9ubHkgaWYgc3RvcmFnZVN1cHBvcnRcbiAgY29uc3QgYXVnbWVudEtleW5hdjogQXVnbWVudEtleW5hdiA9IGFzeW5jIChuYXYsIFtzdG9yYWdlS2V5LCByb290S2V5LCBwYWdlS2V5LCBsYXN0LCBzcGxpY2VBcmdzXSkgPT4ge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBhbGlnbi1hc3NpZ25tZW50cy9hbGlnbi1hc3NpZ25tZW50c1xuICAgIGxldCBhdWdtZW50UGFnZTogKHBhZ2U6IHN0cmluZykgPT4gc3RyaW5nO1xuICAgIGNvbnN0IGJyb3dzZXJLZXkgPSBkb2N1bWVudC5jb29raWUuc3BsaXQoLztcXHMrLykgIC8vIGl0IHdvcmtzIGV2ZW4gaWYgbWFsZm9ybWVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmZpbmQoKHJvdykgPT4gcm93LnN0YXJ0c1dpdGgocGFneSArIFwiPVwiKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/LnNwbGl0KFwiPVwiKVsxXSA/PyByYW5kS2V5KCk7XG4gICAgZG9jdW1lbnQuY29va2llICA9IGAke3BhZ3l9PSR7YnJvd3NlcktleX1gOyAgLy8gU21hbGxlciAubWluIHNpemU6IHNldCB0aGUgY29va2llIHdpdGhvdXQgY2hlY2tpbmdcbiAgICBpZiAoc3RvcmFnZUtleSAmJiAhKHN0b3JhZ2VLZXkgaW4gc3RvcmFnZSkpIHtcbiAgICAgIC8vIFN5bmMgdGhlIHNlc3Npb25nU3RvcmFnZSBmcm9tIG90aGVyIHRhYnMvd2luZG93cyAoZS5nLiwgb3BlbiBwYWdlIGluIHRoZSBuZXcgdGFiL3dpbmRvdylcbiAgICAgIHN5bmMucG9zdE1lc3NhZ2UoPFN5bmNEYXRhPnsgZnJvbTogdGFiSWQsIGtleTogc3RvcmFnZUtleSB9KTtcbiAgICAgIC8vIFdhaXQgZm9yIHRoZSBsaXN0ZW5lciB0byBjb3B5IHRoZSBjdXRvZmZzIGluIHRoZSBjdXJyZW50IHNlc3Npb25TdG9yYWdlXG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZTxzdHJpbmd8bnVsbD4oKHJlc29sdmUpID0+IHNldFRpbWVvdXQoKCkgPT4geyByZXNvbHZlKFwiXCIpIH0sIDEwMCkpO1xuICAgICAgaWYgKCEoc3RvcmFnZUtleSBpbiBzdG9yYWdlKSkgeyAvLyB0aGUgc3RvcmFnZUtleSBkaWRuJ3QgZ2V0IGNvcGllZDogZmFsbGJhY2sgdG8gY291bnRsZXNzIHBhZ2luYXRpb25cbiAgICAgICAgYXVnbWVudFBhZ2UgPSAocGFnZTogc3RyaW5nKSA9PiBgJHtwYWdlfSske1N0cmluZyhsYXN0KX1gOyAgICAgIH1cbiAgICB9XG4gICAgLy8gQHRzLWV4cGVjdC1lcnJvciBJZiBpdCBpcyBub3QgYXNzaWduZWQgaXQgbWVhbnMgaXQgc3VwcG9ydHMga2V5bmF2XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bm5lY2Vzc2FyeS1jb25kaXRpb25cbiAgICBpZiAoIWF1Z21lbnRQYWdlKSB7IC8vIHJlZ3VsYXIga2V5bmF2IHBhZ2luYXRpb25cbiAgICAgIGlmICghc3RvcmFnZUtleSkgeyBkbyB7IHN0b3JhZ2VLZXkgPSByYW5kS2V5KCkgfSB3aGlsZSAoc3RvcmFnZUtleSBpbiBzdG9yYWdlKSB9IC8vIG5vIGR1cCBrZXlzXG4gICAgICBjb25zdCBkYXRhID0gc3RvcmFnZS5nZXRJdGVtKHN0b3JhZ2VLZXkpLFxuICAgICAgICAgIGN1dG9mZnMgPSA8Q3V0b2ZmW10+KGRhdGEgPyBKU09OLnBhcnNlKGRhdGEpIDogW3VuZGVmaW5lZF0pO1xuICAgICAgaWYgKHNwbGljZUFyZ3MpIHtcbiAgICAgICAgY3V0b2Zmcy5zcGxpY2UoLi4uc3BsaWNlQXJncyk7XG4gICAgICAgIHN0b3JhZ2Uuc2V0SXRlbShzdG9yYWdlS2V5LCBKU09OLnN0cmluZ2lmeShjdXRvZmZzKSk7XG4gICAgICB9XG4gICAgICAvLyBBdWdtZW50IGZ1bmN0aW9uXG4gICAgICBhdWdtZW50UGFnZSA9IChwYWdlOnN0cmluZykgPT4ge1xuICAgICAgICBjb25zdCBwYWdlTnVtID0gcGFyc2VJbnQocGFnZSk7XG4gICAgICAgIHJldHVybiBCNjRTYWZlRW5jb2RlKEpTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgPEF1Z21lbnRlZFBhZ2U+W2Jyb3dzZXJLZXksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RvcmFnZUtleSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlTnVtLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1dG9mZnMubGVuZ3RoLCAgICAgICAvLyBwYWdlcy9sYXN0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3V0b2Zmc1twYWdlTnVtIC0gMV0sIC8vIHByaW9yQ3V0b2ZmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3V0b2Zmc1twYWdlTnVtXV0pKTsgIC8vIHBhZ2VDdXRvZmZcbiAgICAgIH07XG4gICAgfVxuICAgIGNvbnN0IHNlYXJjaCA9IChyb290S2V5KSA/IGAke3Jvb3RLZXl9JTVCJHtwYWdlS2V5fSU1RGAgOiBwYWdlS2V5O1xuICAgIGNvbnN0IHJlICAgICA9IG5ldyBSZWdFeHAoYCg/PD1cXFxcPy4qKShcXFxcYiR7c2VhcmNofT0pKFxcXFxkKylgKTtcbiAgICAvLyBBdWdtZW50IHRoZSBwYWdlIHBhcmFtIG9mIGVhY2ggaHJlZlxuICAgIGZvciAoY29uc3QgYSBvZiA8Tm9kZUxpc3RPZjxIVE1MQW5jaG9yRWxlbWVudD4+PHVua25vd24+bmF2LnF1ZXJ5U2VsZWN0b3JBbGwoJ2FbaHJlZl0nKSkge1xuICAgICAgYS5ocmVmID0gYS5ocmVmLnJlcGxhY2UocmUsIChfbWF0Y2gsIHByZWZpeCwgZGlnaXQpOiBzdHJpbmcgPT4gYCR7U3RyaW5nKHByZWZpeCl9JHthdWdtZW50UGFnZSg8c3RyaW5nPmRpZ2l0KX1gKTtcbiAgICB9XG4gICAgLy8gUmV0dXJuIHRoZSBhdWdtZW50IGZ1bmN0aW9uIGZvciBmdXJ0aGVyIGF1Z21lbnRhdGlvbiAoaS5lLiwgdXJsIHRva2VuIGluIGlucHV0X25hdl9qcylcbiAgICByZXR1cm4gYXVnbWVudFBhZ2U7XG4gIH07XG5cbiAgLy8gQnVpbGQgdGhlIHNlcmllc19uYXZfanMgaGVscGVyXG4gIGNvbnN0IGJ1aWxkTmF2SnMgPSAobmF2Ok5hdkpzRWxlbWVudCwgW1tiZWZvcmUsIGFuY2hvciwgY3VycmVudCwgZ2FwLCBhZnRlcl0sIHBhZ2VUb2tlbixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbd2lkdGhzLCBzZXJpZXMsIGxhYmVsc10sIGtleW5hdkFyZ3NdOlNlcmllc05hdkpzQXJncykgPT4ge1xuICAgIGxldCBsYXN0V2lkdGggPSAtMTtcbiAgICBjb25zdCBwYXJlbnQgID0gPEhUTUxFbGVtZW50Pm5hdi5wYXJlbnRFbGVtZW50O1xuXG4gICAgbmF2LnJlbmRlciA9ICgpID0+IHtcbiAgICAgIGNvbnN0IGluZGV4ID0gd2lkdGhzLmZpbmRJbmRleCh3ID0+IHcgPCBwYXJlbnQuY2xpZW50V2lkdGgpO1xuICAgICAgaWYgKGluZGV4ID09PSAtMSB8fCB3aWR0aHNbaW5kZXhdID09PSBsYXN0V2lkdGgpIHsgcmV0dXJuIH1cblxuICAgICAgbGV0IGh0bWwgPSBiZWZvcmU7XG4gICAgICBzZXJpZXNbaW5kZXhdLmZvckVhY2goKGl0ZW0sIGkpID0+IHtcbiAgICAgICAgLy8gQXZvaWQgdGhlIGlmIGJsb2NrcyBhbmQgY2hhaW4gdGhlIHJlc3VsdHMgKHNob3J0ZXIgcGFneS5taW4uanMgYW5kIGVhc2llciByZWFkaW5nKVxuICAgICAgICBodG1sICs9IGl0ZW0gPT0gXCJnYXBcIiA/IGdhcCA6XG4gICAgICAgICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciB0aGUgaXRlbSBtYXkgYmUgYSBudW1iZXIsIGJ1dCB0aGUgJ3JlcGxhY2UnIGNvbnZlcnRzIGl0IHRvIHN0cmluZyAoc2hvcnRlciBwYWd5Lm1pbi5qcylcbiAgICAgICAgICAgICAgICAodHlwZW9mIGl0ZW0gPT0gXCJudW1iZXJcIiA/IGFuY2hvci5yZXBsYWNlKHBhZ2VUb2tlbiwgaXRlbSkgOiBjdXJyZW50KVxuICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShcIkw8XCIsIGxhYmVscz8uW2luZGV4XVtpXSA/PyBgJHtTdHJpbmcoaXRlbSl9PGApO1xuICAgICAgfSk7XG4gICAgICBodG1sICAgICAgICAgKz0gYWZ0ZXI7XG4gICAgICBuYXYuaW5uZXJIVE1MID0gXCJcIjtcbiAgICAgIG5hdi5pbnNlcnRBZGphY2VudEhUTUwoXCJhZnRlcmJlZ2luXCIsIGh0bWwpO1xuICAgICAgbGFzdFdpZHRoID0gd2lkdGhzW2luZGV4XTtcbiAgICAgIGlmIChrZXluYXZBcmdzICYmIHN0b3JhZ2VTdXBwb3J0KSB7IHZvaWQgYXVnbWVudEtleW5hdihuYXYsIGtleW5hdkFyZ3MpIH1cbiAgICB9O1xuXG4gICAgcmpzT2JzZXJ2ZXIub2JzZXJ2ZShwYXJlbnQpO1xuICB9O1xuXG4gIC8vIEluaXQgdGhlIGlucHV0X25hdl9qcyBoZWxwZXJzXG4gIGNvbnN0IGluaXRJbnB1dE5hdkpzID0gYXN5bmMgKG5hdjpIVE1MRWxlbWVudCwgW3VybF90b2tlbiwgcGFnZVRva2VuLCBrZXluYXZBcmdzXTpJbnB1dE5hdkpzQXJncykgPT4ge1xuICAgIGNvbnN0IGF1Z21lbnQgPSBrZXluYXZBcmdzICYmIHN0b3JhZ2VTdXBwb3J0XG4gICAgICAgICAgICAgICAgICAgID8gYXdhaXQgYXVnbWVudEtleW5hdihuYXYsIGtleW5hdkFyZ3MpXG4gICAgICAgICAgICAgICAgICAgIDogKHBhZ2U6IHN0cmluZykgPT4gcGFnZTtcbiAgICBpbml0SW5wdXQobmF2LCBpbnB1dFZhbHVlID0+IHVybF90b2tlbi5yZXBsYWNlKHBhZ2VUb2tlbiwgYXVnbWVudChpbnB1dFZhbHVlKSkpO1xuICB9O1xuXG4gIC8vIEluaXQgdGhlIGxpbWl0X3RhZ19qcyBoZWxwZXJcbiAgY29uc3QgaW5pdExpbWl0VGFnSnMgPSAoc3BhbjpIVE1MU3BhbkVsZW1lbnQsIFtmcm9tLCB1cmxfdG9rZW4sIHBhZ2VfdG9rZW4sIGxpbWl0VG9rZW5dOkxpbWl0VGFnSnNBcmdzKSA9PiB7XG4gICAgaW5pdElucHV0KHNwYW4sIGlucHV0VmFsdWUgPT4ge1xuICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciB0aGUgcGFnZSBpcyBhIG51bWJlciwgYnV0IHRoZSAncmVwbGFjZScgY29udmVydHMgaXQgdG8gc3RyaW5nIChzaG9ydGVyIHBhZ3kubWluLmpzKVxuICAgICAgcmV0dXJuIHVybF90b2tlbi5yZXBsYWNlKHBhZ2VfdG9rZW4sIE1hdGgubWF4KE1hdGguY2VpbChmcm9tIC8gcGFyc2VJbnQoaW5wdXRWYWx1ZSkpLCAxKSlcbiAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShsaW1pdFRva2VuLCBpbnB1dFZhbHVlKTtcbiAgICB9KTtcbiAgfTtcblxuICAvLyBJbml0IHRoZSBpbnB1dCBlbGVtZW50XG4gIGNvbnN0IGluaXRJbnB1dCA9IChlbGVtZW50OkhUTUxFbGVtZW50LCBnZXRVcmw6KHY6c3RyaW5nKSA9PiBzdHJpbmcpID0+IHtcbiAgICBjb25zdCBpbnB1dCAgID0gPEhUTUxJbnB1dEVsZW1lbnQ+ZWxlbWVudC5xdWVyeVNlbGVjdG9yKFwiaW5wdXRcIiksXG4gICAgICAgICAgbGluayAgICA9IDxIVE1MQW5jaG9yRWxlbWVudD5lbGVtZW50LnF1ZXJ5U2VsZWN0b3IoXCJhXCIpO1xuICAgIGxldCAgIGluaXRpYWwgPSBpbnB1dC52YWx1ZTtcbiAgICBjb25zdCBhY3Rpb24gID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgIGlmIChpbnB1dC52YWx1ZSA9PT0gaW5pdGlhbCkgeyByZXR1cm4gfSAgLy8gbm90IGNoYW5nZWRcbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBbbWluLCB2YWwsIG1heF0gPSBbaW5wdXQubWluLCBpbnB1dC52YWx1ZSwgaW5wdXQubWF4XS5tYXAobiA9PiBwYXJzZUludChuKSB8fCAwKTtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAodmFsIDwgbWluIHx8IHZhbCA+IG1heCkgeyAgLy8gcmVzZXQgaW52YWxpZC9vdXQtb2YtcmFuZ2VcbiAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0LnZhbHVlID0gaW5pdGlhbDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0LnNlbGVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsICAgPSBpbnB1dC52YWx1ZTtcbiAgICAgICAgICAgICAgICAgICAgICBsaW5rLmhyZWYgPSBnZXRVcmwoaW5wdXQudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICAgIGxpbmsuY2xpY2soKTtcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICBpbnB1dC5hZGRFdmVudExpc3RlbmVyKFwiZm9jdXNcIiwgKCkgPT4geyBpbnB1dC5zZWxlY3QoKSB9KTtcbiAgICBpbnB1dC5hZGRFdmVudExpc3RlbmVyKFwiZm9jdXNvdXRcIiwgYWN0aW9uKTtcbiAgICBpbnB1dC5hZGRFdmVudExpc3RlbmVyKFwia2V5cHJlc3NcIiwgZSA9PiB7IGlmIChlLmtleSA9PSBcIkVudGVyXCIpIHsgYWN0aW9uKCkgfSB9KTtcbiAgfTtcblxuICAvLyBQdWJsaWMgaW50ZXJmYWNlXG4gIHJldHVybiB7XG4gICAgdmVyc2lvbjogXCI0My42LjJcIixcblxuICAgIC8vIFNjYW4gZm9yIGVsZW1lbnRzIHdpdGggYSBcImRhdGEtcGFneVwiIGF0dHJpYnV0ZSBhbmQgY2FsbCB0aGVpciBpbml0IGZ1bmN0aW9ucyB3aXRoIHRoZSBkZWNvZGVkIGFyZ3NcbiAgICBpbml0KGFyZz86SFRNTEVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IHRhcmdldCA9IGFyZyBpbnN0YW5jZW9mIEhUTUxFbGVtZW50ID8gYXJnIDogZG9jdW1lbnQsXG4gICAgICAgICAgICBlbGVtZW50cyA9IHRhcmdldC5xdWVyeVNlbGVjdG9yQWxsKFwiW2RhdGEtcGFneV1cIik7XG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgPE5vZGVMaXN0T2Y8SFRNTEVsZW1lbnQ+PmVsZW1lbnRzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgW2hlbHBlcklkLCAuLi5hcmdzXSA9IDxJbml0QXJncz5KU09OLnBhcnNlKEI2NERlY29kZSg8c3RyaW5nPmVsZW1lbnQuZ2V0QXR0cmlidXRlKFwiZGF0YS1wYWd5XCIpKSk7XG4gICAgICAgICAgaWYgKGhlbHBlcklkID09IFwia1wiKSB7XG4gICAgICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIHNwcmVhZCAyIGFyZ3VtZW50cywgbm90IDMgYXMgaXQgY29tcGxhaW5zIGFib3V0XG4gICAgICAgICAgICB2b2lkIGF1Z21lbnRLZXluYXYoZWxlbWVudCwgLi4uPEtleW5hdkFyZ3M+PHVua25vd24+YXJncyk7XG4gICAgICAgICAgfSBlbHNlIGlmIChoZWxwZXJJZCA9PSBcInNualwiKSB7XG4gICAgICAgICAgICBidWlsZE5hdkpzKDxOYXZKc0VsZW1lbnQ+ZWxlbWVudCwgPFNlcmllc05hdkpzQXJncz48dW5rbm93bj5hcmdzKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGhlbHBlcklkID09IFwiaW5qXCIpIHtcbiAgICAgICAgICAgIHZvaWQgaW5pdElucHV0TmF2SnMoZWxlbWVudCwgPElucHV0TmF2SnNBcmdzPjx1bmtub3duPmFyZ3MpO1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bm5lY2Vzc2FyeS1jb25kaXRpb25cbiAgICAgICAgICB9IGVsc2UgaWYgKGhlbHBlcklkID09IFwibHRqXCIpIHtcbiAgICAgICAgICAgIGluaXRMaW1pdFRhZ0pzKGVsZW1lbnQsIDxMaW1pdFRhZ0pzQXJncz48dW5rbm93bj5hcmdzKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gZWxzZSB7IGNvbnNvbGUud2FybihcIlBhZ3kuaW5pdDogJW9cXG5Vbmtub3duIGhlbHBlcklkICclcydcIiwgZWxlbWVudCwgaGVscGVySWQpIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7IGNvbnNvbGUud2FybihcIlBhZ3kuaW5pdDogJW9cXG4lc1wiLCBlbGVtZW50LCBlcnIpIH1cbiAgICAgIH1cbiAgICB9XG4gIH07XG59KSgpO1xuIiwKICAgICJpbXBvcnQgUGFneSBmcm9tIFwiLi9wYWd5LnRzXCJcbndpbmRvdy5QYWd5ID0gUGFneVxuIgogIF0sCiAgIm1hcHBpbmdzIjogIjtBQWdEQSxJQUFnQixzQkFBTTtBQUFBLEVBQ3BCLE1BQU0saUJBQWlCLG9CQUFvQixVQUFVLHNCQUFzQjtBQUFBLEVBRTNFLElBQUksT0FBTyxRQUFRLFNBQWtCLE1BQXdCO0FBQUEsRUFDN0QsSUFBSSxnQkFBZ0I7QUFBQSxJQUNsQixVQUFVO0FBQUEsSUFDVixPQUFVLElBQUksaUJBQWlCLElBQUk7QUFBQSxJQUNuQyxRQUFVLEtBQUssSUFBSTtBQUFBLElBR25CLEtBQUssaUJBQWlCLFdBQVcsQ0FBQyxNQUE2QjtBQUFBLE1BQzdELElBQUksRUFBRSxL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
165
+ //# debugId=EE64B5BD0D317BA664756E2164756E21
166
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsicGFneS50cyIsICJwYWd5LXNoaW0udHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbCiAgICAiaW50ZXJmYWNlIFN5bmNEYXRhIHtcbiAgZnJvbT86IG51bWJlclxuICB0bz8gIDogbnVtYmVyXG4gIGtleSAgOiBzdHJpbmdcbiAgc3RyPyA6IHN0cmluZ1xufVxudHlwZSBJbml0QXJncyA9IFtcImtcIiwgIEtleW5hdkFyZ3NdIHwgICAgICAgICAgLy8gc2VyaWVzX25hdltfanNdIHdpdGgga2V5bmF2IGluc3RhbmNlXG4gICAgICAgICAgICAgICAgW1wic25qXCIsIFNlcmllc05hdkpzQXJnc10gfCAgICAvLyBzZXJpZXNfbmF2X2pzXG4gICAgICAgICAgICAgICAgW1wiaW5qXCIsIElucHV0TmF2SnNBcmdzXSB8ICAgICAvLyBpbnB1dF9uYXZfanNcbiAgICAgICAgICAgICAgICBbXCJsdGpcIiwgTGltaXRUYWdKc0FyZ3NdOyAgICAgIC8vIGxpbWl0X3RhZ19qc1xudHlwZSBBdWdtZW50S2V5bmF2ID0gKG5hdjpIVE1MRWxlbWVudCwga2V5bmF2QXJnczpLZXluYXZBcmdzKSA9PiBQcm9taXNlPCgocGFnZTogc3RyaW5nKSA9PiBzdHJpbmcpPjtcbnR5cGUgS2V5bmF2QXJncyA9IHJlYWRvbmx5IFtzdG9yYWdlS2V5IDogc3RyaW5nIHwgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb290S2V5ICAgIDogc3RyaW5nIHwgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlS2V5ICAgIDogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3QgICAgICAgOiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BsaWNlQXJncz86IFNwbGljZUFyZ3NdO1xudHlwZSBTcGxpY2VBcmdzID0gcmVhZG9ubHkgW3N0YXJ0ICAgICAgOiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlQ291bnQ6IG51bWJlciwgICAgIC8vIGl0IHdvdWxkIGJlIG9wdGlvbmFsLCBidXQgdHMgY29tcGxhaW5zXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uaXRlbXM6ICAgIEN1dG9mZltdXTtcbnR5cGUgQ3V0b2ZmID0gcmVhZG9ubHkgKHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4pW107XG50eXBlIEF1Z21lbnRlZFBhZ2UgPSBbYnJvd3NlcklkICA6IHN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgICBzdG9yYWdlS2V5IDogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgIHBhZ2VOdW1iZXIgOiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgcGFnZXMgICAgICA6IG51bWJlcixcbiAgICAgICAgICAgICAgICAgICAgICBwcmlvckN1dG9mZjogQ3V0b2ZmIHwgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICBwYWdlQ3V0b2ZmIDogQ3V0b2ZmIHwgbnVsbF07XG50eXBlIFNlcmllc05hdkpzQXJncyA9IHJlYWRvbmx5IFtOYXZKc1Rva2VucywgcGFnZVRva2VuOiBzdHJpbmcsIE5hdkpzU2VyaWVzLCBLZXluYXZBcmdzP107XG50eXBlIE5hdkpzU2VyaWVzID0gcmVhZG9ubHkgW3dpZHRoczogbnVtYmVyW10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllczogKHN0cmluZyB8IG51bWJlcilbXVtdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM6IHN0cmluZ1tdW10gfCBudWxsXTtcbnR5cGUgSW5wdXROYXZKc0FyZ3MgPSByZWFkb25seSBbdXJsVG9rZW46ICBzdHJpbmcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VUb2tlbjogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBLZXluYXZBcmdzP107XG50eXBlIExpbWl0VGFnSnNBcmdzID0gcmVhZG9ubHkgW2Zyb20gICAgICA6IG51bWJlcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXJsVG9rZW4gIDogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlVG9rZW4gOiBzdHJpbmcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0VG9rZW46IHN0cmluZ107XG50eXBlIE5hdkpzVG9rZW5zID0gcmVhZG9ubHkgW2JlZm9yZSA6IHN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5jaG9yIDogc3RyaW5nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50OiBzdHJpbmcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdhcCAgICA6IHN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWZ0ZXIgIDogc3RyaW5nXTtcbmludGVyZmFjZSBOYXZKc0VsZW1lbnQgZXh0ZW5kcyBIVE1MRWxlbWVudCB7XG4gIHJlbmRlcigpOiB2b2lkXG59XG5cbi8vIFRoZSBzeW50YXggdXNlZCBpbiB0aGlzIGZpbGUgaGFzIGJlZW4gY2FyZWZ1bGx5IGNvbXBvc2VkIHRvIG1pbmltaXplXG4vLyB0aGUgcGFneS5taW4uanMgc2l6ZSBhbmQgYXZvaWQgcG9sbHV0aW9uIGluIHRoZSB3aW5kb3cgb2JqZWN0LlxuZXhwb3J0IGRlZmF1bHQgKCgpID0+IHtcbiAgY29uc3Qgc3RvcmFnZVN1cHBvcnQgPSAnc2Vzc2lvblN0b3JhZ2UnIGluIHdpbmRvdyAmJiAnQnJvYWRjYXN0Q2hhbm5lbCcgaW4gd2luZG93O1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcHJlZmVyLWNvbnN0XG4gIGxldCBwYWd5ID0gXCJwYWd5XCIsIHN0b3JhZ2U6IFN0b3JhZ2UsIHN5bmM6IEJyb2FkY2FzdENoYW5uZWwsIHRhYklkOiBudW1iZXI7XG4gIGlmIChzdG9yYWdlU3VwcG9ydCkge1xuICAgIHN0b3JhZ2UgPSBzZXNzaW9uU3RvcmFnZTsgLy8gc2hvcnRlbiB0aGUgY29tcGlsZWQgc2l6ZVxuICAgIHN5bmMgICAgPSBuZXcgQnJvYWRjYXN0Q2hhbm5lbChwYWd5KTtcbiAgICB0YWJJZCAgID0gRGF0ZS5ub3coKTtcblxuICAgIC8vIFN5bmMgdGhlIHNlc3Npb25TdG9yYWdlIGtleXMgZm9yIHRoZSBjdXRvZmZzIG9wZW5lZCBpbiBhIG5ldyB0YWIvd2luZG93XG4gICAgc3luYy5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCAoZTpNZXNzYWdlRXZlbnQ8U3luY0RhdGE+KSA9PiB7XG4gICAgICBpZiAoZS5kYXRhLmZyb20pIHsgLy8gcmVxdWVzdCBjdXRvZmZzXG4gICAgICAgIGNvbnN0IGN1dG9mZnMgPSBzdG9yYWdlLmdldEl0ZW0oZS5kYXRhLmtleSk7XG4gICAgICAgIGlmIChjdXRvZmZzKSB7XG4gICAgICAgICAgc3luYy5wb3N0TWVzc2FnZSg8U3luY0RhdGE+e3RvOiBlLmRhdGEuZnJvbSwga2V5OiBlLmRhdGEua2V5LCBzdHI6IGN1dG9mZnN9KTtcbiAgICAgICAgfSAvLyBzZW5kIHJlc3BvbnNlXG4gICAgICB9IGVsc2UgaWYgKGUuZGF0YS50bykgeyAgLy8gcmVjZWl2ZSBjdXRvZmZzXG4gICAgICAgIGlmIChlLmRhdGEudG8gPT0gdGFiSWQpIHtcbiAgICAgICAgICBzdG9yYWdlLnNldEl0ZW0oZS5kYXRhLmtleSwgPHN0cmluZz5lLmRhdGEuc3RyKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9XG4gIC8vIFRoZSBvYnNlcnZlciBpbnN0YW5jZSBmb3IgcmVzcG9uc2l2ZSBuYXZzXG4gIGNvbnN0IHJqc09ic2VydmVyID0gbmV3IFJlc2l6ZU9ic2VydmVyKGVudHJpZXMgPT4ge1xuICAgIGVudHJpZXMuZm9yRWFjaChlID0+IHtcbiAgICAgIGUudGFyZ2V0LnF1ZXJ5U2VsZWN0b3JBbGw8TmF2SnNFbGVtZW50PihcIi5zZXJpZXMtbmF2LWpzXCIpLmZvckVhY2goZWwgPT4ge1xuICAgICAgICBlbC5yZW5kZXIoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICAvKiBGdWxsIHNldCBvZiBCNjQgZnVuY3Rpb25zXG4gIGNvbnN0IEI2NEVuY29kZSAgICAgPSAodW5pY29kZTpzdHJpbmcpID0+IGJ0b2EoU3RyaW5nLmZyb21DaGFyQ29kZSguLi4obmV3IFRleHRFbmNvZGVyKS5lbmNvZGUodW5pY29kZSkpKSxcbiAgICAgICAgQjY0U2FmZSAgICAgICA9ICh1bnNhZmU6c3RyaW5nKSAgPT4gdW5zYWZlLnJlcGxhY2UoL1srLz1dL2csIChtKSA9PiBtID09IFwiK1wiID8gXCItXCIgOiBtID09IFwiL1wiID8gXCJfXCIgOiBcIlwiKSxcbiAgICAgICAgQjY0U2FmZUVuY29kZSA9ICh1bmljb2RlOnN0cmluZykgPT4gQjY0U2FmZShCNjRFbmNvZGUodW5pY29kZSkpLFxuICAgICAgICBCNjREZWNvZGUgICAgID0gKGJhc2U2NDpzdHJpbmcpICA9PiAobmV3IFRleHREZWNvZGVyKCkpLmRlY29kZShVaW50OEFycmF5LmZyb20oYXRvYihiYXNlNjQpLCBjID0+IGMuY2hhckNvZGVBdCgwKSkpLFxuICAgICAgICBCNjRVbnNhZmUgICAgID0gKHNhZmU6c3RyaW5nKSAgICA9PiBzYWZlLnJlcGxhY2UoL1stX10vZywgKG1hdGNoKSA9PiBtYXRjaCA9PSBcIi1cIiA/IFwiK1wiIDogXCIvXCIpLFxuICAgICAgICBCNjRTYWZlRGVjb2RlID0gKGJhc2U2NDpzdHJpbmcpICA9PiBCNjREZWNvZGUoQjY0VW5zYWZlKGJhc2U2NCkpXG4gICovXG4gIGNvbnN0IEI2NFNhZmVFbmNvZGUgPSAodW5pY29kZTpzdHJpbmcpID0+IGJ0b2EoU3RyaW5nLmZyb21DaGFyQ29kZSguLi4obmV3IFRleHRFbmNvZGVyKS5lbmNvZGUodW5pY29kZSkpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoL1srLz1dL2csIChtKSA9PiBtID09IFwiK1wiID8gXCItXCIgOiBtID09IFwiL1wiID8gXCJfXCIgOiBcIlwiKSxcbiAgICAgICAgQjY0RGVjb2RlICAgICA9IChiYXNlNjQ6c3RyaW5nKSAgPT4gKG5ldyBUZXh0RGVjb2RlcigpKS5kZWNvZGUoVWludDhBcnJheS5mcm9tKGF0b2IoYmFzZTY0KSwgYyA9PiBjLmNoYXJDb2RlQXQoMCkpKTtcblxuICAvLyBSZXR1cm4gYSByYW5kb20ga2V5OiAzIGNoYXJzIG1heCwgYmFzZS0zNiBudW1iZXIgPCAzNioqM1xuICBjb25zdCByYW5kS2V5ID0gKCkgPT4gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMzYgKiogMykudG9TdHJpbmcoMzYpO1xuXG4gIC8vIE1hbmFnZSB0aGUgcGFnZSBhdWdtZW50YXRpb24gZm9yIEtleW5hdiwgY2FsbGVkIG9ubHkgaWYgc3RvcmFnZVN1cHBvcnRcbiAgY29uc3QgYXVnbWVudEtleW5hdjogQXVnbWVudEtleW5hdiA9IGFzeW5jIChuYXYsIFtzdG9yYWdlS2V5LCByb290S2V5LCBwYWdlS2V5LCBsYXN0LCBzcGxpY2VBcmdzXSkgPT4ge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBhbGlnbi1hc3NpZ25tZW50cy9hbGlnbi1hc3NpZ25tZW50c1xuICAgIGxldCBhdWdtZW50UGFnZTogKHBhZ2U6IHN0cmluZykgPT4gc3RyaW5nO1xuICAgIGNvbnN0IGJyb3dzZXJLZXkgPSBkb2N1bWVudC5jb29raWUuc3BsaXQoLztcXHMrLykgIC8vIGl0IHdvcmtzIGV2ZW4gaWYgbWFsZm9ybWVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmZpbmQoKHJvdykgPT4gcm93LnN0YXJ0c1dpdGgocGFneSArIFwiPVwiKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/LnNwbGl0KFwiPVwiKVsxXSA/PyByYW5kS2V5KCk7XG4gICAgZG9jdW1lbnQuY29va2llICA9IGAke3BhZ3l9PSR7YnJvd3NlcktleX1gOyAgLy8gU21hbGxlciAubWluIHNpemU6IHNldCB0aGUgY29va2llIHdpdGhvdXQgY2hlY2tpbmdcbiAgICBpZiAoc3RvcmFnZUtleSAmJiAhKHN0b3JhZ2VLZXkgaW4gc3RvcmFnZSkpIHtcbiAgICAgIC8vIFN5bmMgdGhlIHNlc3Npb25nU3RvcmFnZSBmcm9tIG90aGVyIHRhYnMvd2luZG93cyAoZS5nLiwgb3BlbiBwYWdlIGluIHRoZSBuZXcgdGFiL3dpbmRvdylcbiAgICAgIHN5bmMucG9zdE1lc3NhZ2UoPFN5bmNEYXRhPnsgZnJvbTogdGFiSWQsIGtleTogc3RvcmFnZUtleSB9KTtcbiAgICAgIC8vIFdhaXQgZm9yIHRoZSBsaXN0ZW5lciB0byBjb3B5IHRoZSBjdXRvZmZzIGluIHRoZSBjdXJyZW50IHNlc3Npb25TdG9yYWdlXG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZTxzdHJpbmd8bnVsbD4oKHJlc29sdmUpID0+IHNldFRpbWVvdXQoKCkgPT4geyByZXNvbHZlKFwiXCIpIH0sIDEwMCkpO1xuICAgICAgaWYgKCEoc3RvcmFnZUtleSBpbiBzdG9yYWdlKSkgeyAvLyB0aGUgc3RvcmFnZUtleSBkaWRuJ3QgZ2V0IGNvcGllZDogZmFsbGJhY2sgdG8gY291bnRsZXNzIHBhZ2luYXRpb25cbiAgICAgICAgYXVnbWVudFBhZ2UgPSAocGFnZTogc3RyaW5nKSA9PiBgJHtwYWdlfSske1N0cmluZyhsYXN0KX1gOyAgICAgIH1cbiAgICB9XG4gICAgLy8gQHRzLWV4cGVjdC1lcnJvciBJZiBpdCBpcyBub3QgYXNzaWduZWQgaXQgbWVhbnMgaXQgc3VwcG9ydHMga2V5bmF2XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bm5lY2Vzc2FyeS1jb25kaXRpb25cbiAgICBpZiAoIWF1Z21lbnRQYWdlKSB7IC8vIHJlZ3VsYXIga2V5bmF2IHBhZ2luYXRpb25cbiAgICAgIGlmICghc3RvcmFnZUtleSkgeyBkbyB7IHN0b3JhZ2VLZXkgPSByYW5kS2V5KCkgfSB3aGlsZSAoc3RvcmFnZUtleSBpbiBzdG9yYWdlKSB9IC8vIG5vIGR1cCBrZXlzXG4gICAgICBjb25zdCBkYXRhID0gc3RvcmFnZS5nZXRJdGVtKHN0b3JhZ2VLZXkpLFxuICAgICAgICAgIGN1dG9mZnMgPSA8Q3V0b2ZmW10+KGRhdGEgPyBKU09OLnBhcnNlKGRhdGEpIDogW3VuZGVmaW5lZF0pO1xuICAgICAgaWYgKHNwbGljZUFyZ3MpIHtcbiAgICAgICAgY3V0b2Zmcy5zcGxpY2UoLi4uc3BsaWNlQXJncyk7XG4gICAgICAgIHN0b3JhZ2Uuc2V0SXRlbShzdG9yYWdlS2V5LCBKU09OLnN0cmluZ2lmeShjdXRvZmZzKSk7XG4gICAgICB9XG4gICAgICAvLyBBdWdtZW50IGZ1bmN0aW9uXG4gICAgICBhdWdtZW50UGFnZSA9IChwYWdlOnN0cmluZykgPT4ge1xuICAgICAgICBjb25zdCBwYWdlTnVtID0gcGFyc2VJbnQocGFnZSk7XG4gICAgICAgIHJldHVybiBCNjRTYWZlRW5jb2RlKEpTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgPEF1Z21lbnRlZFBhZ2U+W2Jyb3dzZXJLZXksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RvcmFnZUtleSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlTnVtLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1dG9mZnMubGVuZ3RoLCAgICAgICAvLyBwYWdlcy9sYXN0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3V0b2Zmc1twYWdlTnVtIC0gMV0sIC8vIHByaW9yQ3V0b2ZmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3V0b2Zmc1twYWdlTnVtXV0pKTsgIC8vIHBhZ2VDdXRvZmZcbiAgICAgIH07XG4gICAgfVxuICAgIGNvbnN0IHNlYXJjaCA9IChyb290S2V5KSA/IGAke3Jvb3RLZXl9JTVCJHtwYWdlS2V5fSU1RGAgOiBwYWdlS2V5O1xuICAgIGNvbnN0IHJlICAgICA9IG5ldyBSZWdFeHAoYCg/PD1cXFxcPy4qKShcXFxcYiR7c2VhcmNofT0pKFxcXFxkKylgKTtcbiAgICAvLyBBdWdtZW50IHRoZSBwYWdlIHBhcmFtIG9mIGVhY2ggaHJlZlxuICAgIGZvciAoY29uc3QgYSBvZiA8Tm9kZUxpc3RPZjxIVE1MQW5jaG9yRWxlbWVudD4+PHVua25vd24+bmF2LnF1ZXJ5U2VsZWN0b3JBbGwoJ2FbaHJlZl0nKSkge1xuICAgICAgYS5ocmVmID0gYS5ocmVmLnJlcGxhY2UocmUsIChfbWF0Y2gsIHByZWZpeCwgZGlnaXQpOiBzdHJpbmcgPT4gYCR7U3RyaW5nKHByZWZpeCl9JHthdWdtZW50UGFnZSg8c3RyaW5nPmRpZ2l0KX1gKTtcbiAgICB9XG4gICAgLy8gUmV0dXJuIHRoZSBhdWdtZW50IGZ1bmN0aW9uIGZvciBmdXJ0aGVyIGF1Z21lbnRhdGlvbiAoaS5lLiwgdXJsIHRva2VuIGluIGlucHV0X25hdl9qcylcbiAgICByZXR1cm4gYXVnbWVudFBhZ2U7XG4gIH07XG5cbiAgLy8gQnVpbGQgdGhlIHNlcmllc19uYXZfanMgaGVscGVyXG4gIGNvbnN0IGJ1aWxkTmF2SnMgPSAobmF2Ok5hdkpzRWxlbWVudCwgW1tiZWZvcmUsIGFuY2hvciwgY3VycmVudCwgZ2FwLCBhZnRlcl0sIHBhZ2VUb2tlbixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbd2lkdGhzLCBzZXJpZXMsIGxhYmVsc10sIGtleW5hdkFyZ3NdOlNlcmllc05hdkpzQXJncykgPT4ge1xuICAgIGxldCBsYXN0V2lkdGggPSAtMTtcbiAgICBjb25zdCBwYXJlbnQgID0gPEhUTUxFbGVtZW50Pm5hdi5wYXJlbnRFbGVtZW50O1xuXG4gICAgbmF2LnJlbmRlciA9ICgpID0+IHtcbiAgICAgIGNvbnN0IGluZGV4ID0gd2lkdGhzLmZpbmRJbmRleCh3ID0+IHcgPCBwYXJlbnQuY2xpZW50V2lkdGgpO1xuICAgICAgaWYgKGluZGV4ID09PSAtMSB8fCB3aWR0aHNbaW5kZXhdID09PSBsYXN0V2lkdGgpIHsgcmV0dXJuIH1cblxuICAgICAgbGV0IGh0bWwgPSBiZWZvcmU7XG4gICAgICBzZXJpZXNbaW5kZXhdLmZvckVhY2goKGl0ZW0sIGkpID0+IHtcbiAgICAgICAgLy8gQXZvaWQgdGhlIGlmIGJsb2NrcyBhbmQgY2hhaW4gdGhlIHJlc3VsdHMgKHNob3J0ZXIgcGFneS5taW4uanMgYW5kIGVhc2llciByZWFkaW5nKVxuICAgICAgICBodG1sICs9IGl0ZW0gPT0gXCJnYXBcIiA/IGdhcCA6XG4gICAgICAgICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciB0aGUgaXRlbSBtYXkgYmUgYSBudW1iZXIsIGJ1dCB0aGUgJ3JlcGxhY2UnIGNvbnZlcnRzIGl0IHRvIHN0cmluZyAoc2hvcnRlciBwYWd5Lm1pbi5qcylcbiAgICAgICAgICAgICAgICAodHlwZW9mIGl0ZW0gPT0gXCJudW1iZXJcIiA/IGFuY2hvci5yZXBsYWNlKHBhZ2VUb2tlbiwgaXRlbSkgOiBjdXJyZW50KVxuICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShcIkw8XCIsIGxhYmVscz8uW2luZGV4XVtpXSA/PyBgJHtTdHJpbmcoaXRlbSl9PGApO1xuICAgICAgfSk7XG4gICAgICBodG1sICAgICAgICAgKz0gYWZ0ZXI7XG4gICAgICBuYXYuaW5uZXJIVE1MID0gXCJcIjtcbiAgICAgIG5hdi5pbnNlcnRBZGphY2VudEhUTUwoXCJhZnRlcmJlZ2luXCIsIGh0bWwpO1xuICAgICAgbGFzdFdpZHRoID0gd2lkdGhzW2luZGV4XTtcbiAgICAgIGlmIChrZXluYXZBcmdzICYmIHN0b3JhZ2VTdXBwb3J0KSB7IHZvaWQgYXVnbWVudEtleW5hdihuYXYsIGtleW5hdkFyZ3MpIH1cbiAgICB9O1xuXG4gICAgcmpzT2JzZXJ2ZXIub2JzZXJ2ZShwYXJlbnQpO1xuICB9O1xuXG4gIC8vIEluaXQgdGhlIGlucHV0X25hdl9qcyBoZWxwZXJzXG4gIGNvbnN0IGluaXRJbnB1dE5hdkpzID0gYXN5bmMgKG5hdjpIVE1MRWxlbWVudCwgW3VybF90b2tlbiwgcGFnZVRva2VuLCBrZXluYXZBcmdzXTpJbnB1dE5hdkpzQXJncykgPT4ge1xuICAgIGNvbnN0IGF1Z21lbnQgPSBrZXluYXZBcmdzICYmIHN0b3JhZ2VTdXBwb3J0XG4gICAgICAgICAgICAgICAgICAgID8gYXdhaXQgYXVnbWVudEtleW5hdihuYXYsIGtleW5hdkFyZ3MpXG4gICAgICAgICAgICAgICAgICAgIDogKHBhZ2U6IHN0cmluZykgPT4gcGFnZTtcbiAgICBpbml0SW5wdXQobmF2LCBpbnB1dFZhbHVlID0+IHVybF90b2tlbi5yZXBsYWNlKHBhZ2VUb2tlbiwgYXVnbWVudChpbnB1dFZhbHVlKSkpO1xuICB9O1xuXG4gIC8vIEluaXQgdGhlIGxpbWl0X3RhZ19qcyBoZWxwZXJcbiAgY29uc3QgaW5pdExpbWl0VGFnSnMgPSAoc3BhbjpIVE1MU3BhbkVsZW1lbnQsIFtmcm9tLCB1cmxfdG9rZW4sIHBhZ2VfdG9rZW4sIGxpbWl0VG9rZW5dOkxpbWl0VGFnSnNBcmdzKSA9PiB7XG4gICAgaW5pdElucHV0KHNwYW4sIGlucHV0VmFsdWUgPT4ge1xuICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciB0aGUgcGFnZSBpcyBhIG51bWJlciwgYnV0IHRoZSAncmVwbGFjZScgY29udmVydHMgaXQgdG8gc3RyaW5nIChzaG9ydGVyIHBhZ3kubWluLmpzKVxuICAgICAgcmV0dXJuIHVybF90b2tlbi5yZXBsYWNlKHBhZ2VfdG9rZW4sIE1hdGgubWF4KE1hdGguY2VpbChmcm9tIC8gcGFyc2VJbnQoaW5wdXRWYWx1ZSkpLCAxKSlcbiAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZShsaW1pdFRva2VuLCBpbnB1dFZhbHVlKTtcbiAgICB9KTtcbiAgfTtcblxuICAvLyBJbml0IHRoZSBpbnB1dCBlbGVtZW50XG4gIGNvbnN0IGluaXRJbnB1dCA9IChlbGVtZW50OkhUTUxFbGVtZW50LCBnZXRVcmw6KHY6c3RyaW5nKSA9PiBzdHJpbmcpID0+IHtcbiAgICBjb25zdCBpbnB1dCAgID0gPEhUTUxJbnB1dEVsZW1lbnQ+ZWxlbWVudC5xdWVyeVNlbGVjdG9yKFwiaW5wdXRcIiksXG4gICAgICAgICAgbGluayAgICA9IDxIVE1MQW5jaG9yRWxlbWVudD5lbGVtZW50LnF1ZXJ5U2VsZWN0b3IoXCJhXCIpO1xuICAgIGxldCAgIGluaXRpYWwgPSBpbnB1dC52YWx1ZTtcbiAgICBjb25zdCBhY3Rpb24gID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgIGlmIChpbnB1dC52YWx1ZSA9PT0gaW5pdGlhbCkgeyByZXR1cm4gfSAgLy8gbm90IGNoYW5nZWRcbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBbbWluLCB2YWwsIG1heF0gPSBbaW5wdXQubWluLCBpbnB1dC52YWx1ZSwgaW5wdXQubWF4XS5tYXAobiA9PiBwYXJzZUludChuKSB8fCAwKTtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAodmFsIDwgbWluIHx8IHZhbCA+IG1heCkgeyAgLy8gcmVzZXQgaW52YWxpZC9vdXQtb2YtcmFuZ2VcbiAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0LnZhbHVlID0gaW5pdGlhbDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0LnNlbGVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICBpbml0aWFsICAgPSBpbnB1dC52YWx1ZTtcbiAgICAgICAgICAgICAgICAgICAgICBsaW5rLmhyZWYgPSBnZXRVcmwoaW5wdXQudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICAgIGxpbmsuY2xpY2soKTtcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICBpbnB1dC5hZGRFdmVudExpc3RlbmVyKFwiZm9jdXNcIiwgKCkgPT4geyBpbnB1dC5zZWxlY3QoKSB9KTtcbiAgICBpbnB1dC5hZGRFdmVudExpc3RlbmVyKFwiZm9jdXNvdXRcIiwgYWN0aW9uKTtcbiAgICBpbnB1dC5hZGRFdmVudExpc3RlbmVyKFwia2V5cHJlc3NcIiwgZSA9PiB7IGlmIChlLmtleSA9PSBcIkVudGVyXCIpIHsgYWN0aW9uKCkgfSB9KTtcbiAgfTtcblxuICAvLyBQdWJsaWMgaW50ZXJmYWNlXG4gIHJldHVybiB7XG4gICAgdmVyc2lvbjogXCI0My43LjBcIixcblxuICAgIC8vIFNjYW4gZm9yIGVsZW1lbnRzIHdpdGggYSBcImRhdGEtcGFneVwiIGF0dHJpYnV0ZSBhbmQgY2FsbCB0aGVpciBpbml0IGZ1bmN0aW9ucyB3aXRoIHRoZSBkZWNvZGVkIGFyZ3NcbiAgICBpbml0KGFyZz86SFRNTEVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IHRhcmdldCA9IGFyZyBpbnN0YW5jZW9mIEhUTUxFbGVtZW50ID8gYXJnIDogZG9jdW1lbnQsXG4gICAgICAgICAgICBlbGVtZW50cyA9IHRhcmdldC5xdWVyeVNlbGVjdG9yQWxsKFwiW2RhdGEtcGFneV1cIik7XG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgPE5vZGVMaXN0T2Y8SFRNTEVsZW1lbnQ+PmVsZW1lbnRzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgW2hlbHBlcklkLCAuLi5hcmdzXSA9IDxJbml0QXJncz5KU09OLnBhcnNlKEI2NERlY29kZSg8c3RyaW5nPmVsZW1lbnQuZ2V0QXR0cmlidXRlKFwiZGF0YS1wYWd5XCIpKSk7XG4gICAgICAgICAgaWYgKGhlbHBlcklkID09IFwia1wiKSB7XG4gICAgICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIHNwcmVhZCAyIGFyZ3VtZW50cywgbm90IDMgYXMgaXQgY29tcGxhaW5zIGFib3V0XG4gICAgICAgICAgICB2b2lkIGF1Z21lbnRLZXluYXYoZWxlbWVudCwgLi4uPEtleW5hdkFyZ3M+PHVua25vd24+YXJncyk7XG4gICAgICAgICAgfSBlbHNlIGlmIChoZWxwZXJJZCA9PSBcInNualwiKSB7XG4gICAgICAgICAgICBidWlsZE5hdkpzKDxOYXZKc0VsZW1lbnQ+ZWxlbWVudCwgPFNlcmllc05hdkpzQXJncz48dW5rbm93bj5hcmdzKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGhlbHBlcklkID09IFwiaW5qXCIpIHtcbiAgICAgICAgICAgIHZvaWQgaW5pdElucHV0TmF2SnMoZWxlbWVudCwgPElucHV0TmF2SnNBcmdzPjx1bmtub3duPmFyZ3MpO1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bm5lY2Vzc2FyeS1jb25kaXRpb25cbiAgICAgICAgICB9IGVsc2UgaWYgKGhlbHBlcklkID09IFwibHRqXCIpIHtcbiAgICAgICAgICAgIGluaXRMaW1pdFRhZ0pzKGVsZW1lbnQsIDxMaW1pdFRhZ0pzQXJncz48dW5rbm93bj5hcmdzKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gZWxzZSB7IGNvbnNvbGUud2FybihcIlBhZ3kuaW5pdDogJW9cXG5Vbmtub3duIGhlbHBlcklkICclcydcIiwgZWxlbWVudCwgaGVscGVySWQpIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7IGNvbnNvbGUud2FybihcIlBhZ3kuaW5pdDogJW9cXG4lc1wiLCBlbGVtZW50LCBlcnIpIH1cbiAgICAgIH1cbiAgICB9XG4gIH07XG59KSgpO1xuIiwKICAgICJpbXBvcnQgUGFneSBmcm9tIFwiLi9wYWd5LnRzXCJcbndpbmRvdy5QYWd5ID0gUGFneVxuIgogIF0sCiAgIm1hcHBpbmdzIjogIjtBQWdEQSxJQUFnQixzQkFBTTtBQUFBLEVBQ3BCLE1BQU0saUJBQWlCLG9CQUFvQixVQUFVLHNCQUFzQjtBQUFBLEVBRTNFLElBQUksT0FBTyxRQUFRLFNBQWtCLE1BQXdCO0FBQUEsRUFDN0QsSUFBSSxnQkFBZ0I7QUFBQSxJQUNsQixVQUFVO0FBQUEsSUFDVixPQUFVLElBQUksaUJBQWlCLElBQUk7QUFBQSxJQUNuQyxRQUFVLEtBQUssSUFBSTtBQUFBLElBR25CLEtBQUssaUJBQWlCLFdBQVcsQ0FBQyxNQUE2QjtBQUFBLE1BQzdELElBQUksRUFBRSxL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
@@ -1,2 +1,2 @@
1
- window.Pagy=(()=>{let O="sessionStorage"in window&&"BroadcastChannel"in window,B="pagy",Z,L,W;if(O)Z=sessionStorage,L=new BroadcastChannel(B),W=Date.now(),L.addEventListener("message",(q)=>{if(q.data.from){let z=Z.getItem(q.data.key);if(z)L.postMessage({to:q.data.from,key:q.data.key,str:z})}else if(q.data.to){if(q.data.to==W)Z.setItem(q.data.key,q.data.str)}});let V=new ResizeObserver((q)=>{q.forEach((z)=>{z.target.querySelectorAll(".series-nav-js").forEach((C)=>{C.render()})})}),_=(q)=>btoa(String.fromCharCode(...new TextEncoder().encode(q))).replace(/[+/=]/g,(z)=>z=="+"?"-":z=="/"?"_":""),T=(q)=>new TextDecoder().decode(Uint8Array.from(atob(q),(z)=>z.charCodeAt(0))),P=()=>Math.floor(Math.random()*46656).toString(36),J=async(q,[z,C,F,H,G])=>{let Q,X=document.cookie.split(/;\s+/).find((M)=>M.startsWith(B+"="))?.split("=")[1]??P();if(document.cookie=`${B}=${X}`,z&&!(z in Z)){if(L.postMessage({from:W,key:z}),await new Promise((M)=>setTimeout(()=>{M("")},100)),!(z in Z))Q=(M)=>`${M}+${String(H)}`}if(!Q){if(!z)do z=P();while(z in Z);let M=Z.getItem(z),Y=M?JSON.parse(M):[void 0];if(G)Y.splice(...G),Z.setItem(z,JSON.stringify(Y));Q=($)=>{let R=parseInt($);return _(JSON.stringify([X,z,R,Y.length,Y[R-1],Y[R]]))}}let D=C?`${C}%5B${F}%5D`:F,E=new RegExp(`(?<=\\?.*)(\\b${D}=)(\\d+)`);for(let M of q.querySelectorAll("a[href]"))M.href=M.href.replace(E,(Y,$,R)=>`${String($)}${Q(R)}`);return Q},x=(q,[[z,C,F,H,G],Q,[X,D,E],M])=>{let Y=-1,$=q.parentElement;q.render=()=>{let R=X.findIndex((j)=>j<$.clientWidth);if(R===-1||X[R]===Y)return;let U=z;if(D[R].forEach((j,I)=>{U+=j=="gap"?H:(typeof j=="number"?C.replace(Q,j):F).replace("L<",E?.[R][I]??`${String(j)}<`)}),U+=G,q.innerHTML="",q.insertAdjacentHTML("afterbegin",U),Y=X[R],M&&O)J(q,M)},V.observe($)},w=async(q,[z,C,F])=>{let H=F&&O?await J(q,F):(G)=>G;S(q,(G)=>z.replace(C,H(G)))},A=(q,[z,C,F,H])=>{S(q,(G)=>{return C.replace(F,Math.max(Math.ceil(z/parseInt(G)),1)).replace(H,G)})},S=(q,z)=>{let C=q.querySelector("input"),F=q.querySelector("a"),H=C.value,G=()=>{if(C.value===H)return;let[Q,X,D]=[C.min,C.value,C.max].map((E)=>parseInt(E)||0);if(X<Q||X>D){C.value=H,C.select();return}H=C.value,F.href=z(C.value),F.click()};C.addEventListener("focus",()=>{C.select()}),C.addEventListener("focusout",G),C.addEventListener("keypress",(Q)=>{if(Q.key=="Enter")G()})};return{version:"43.6.2",init(q){let z=q instanceof HTMLElement?q:document,C=z.querySelectorAll("[data-pagy]");for(let F of C)try{let[H,...G]=JSON.parse(T(F.getAttribute("data-pagy")));if(H=="k")J(F,...G);else if(H=="snj")x(F,G);else if(H=="inj")w(F,G);else if(H=="ltj")A(F,G)}catch(H){console.warn(`Pagy.init: %o
1
+ window.Pagy=(()=>{let O="sessionStorage"in window&&"BroadcastChannel"in window,B="pagy",Z,L,W;if(O)Z=sessionStorage,L=new BroadcastChannel(B),W=Date.now(),L.addEventListener("message",(q)=>{if(q.data.from){let z=Z.getItem(q.data.key);if(z)L.postMessage({to:q.data.from,key:q.data.key,str:z})}else if(q.data.to){if(q.data.to==W)Z.setItem(q.data.key,q.data.str)}});let V=new ResizeObserver((q)=>{q.forEach((z)=>{z.target.querySelectorAll(".series-nav-js").forEach((C)=>{C.render()})})}),_=(q)=>btoa(String.fromCharCode(...new TextEncoder().encode(q))).replace(/[+/=]/g,(z)=>z=="+"?"-":z=="/"?"_":""),T=(q)=>new TextDecoder().decode(Uint8Array.from(atob(q),(z)=>z.charCodeAt(0))),P=()=>Math.floor(Math.random()*46656).toString(36),J=async(q,[z,C,F,H,G])=>{let Q,X=document.cookie.split(/;\s+/).find((M)=>M.startsWith(B+"="))?.split("=")[1]??P();if(document.cookie=`${B}=${X}`,z&&!(z in Z)){if(L.postMessage({from:W,key:z}),await new Promise((M)=>setTimeout(()=>{M("")},100)),!(z in Z))Q=(M)=>`${M}+${String(H)}`}if(!Q){if(!z)do z=P();while(z in Z);let M=Z.getItem(z),Y=M?JSON.parse(M):[void 0];if(G)Y.splice(...G),Z.setItem(z,JSON.stringify(Y));Q=($)=>{let R=parseInt($);return _(JSON.stringify([X,z,R,Y.length,Y[R-1],Y[R]]))}}let D=C?`${C}%5B${F}%5D`:F,E=new RegExp(`(?<=\\?.*)(\\b${D}=)(\\d+)`);for(let M of q.querySelectorAll("a[href]"))M.href=M.href.replace(E,(Y,$,R)=>`${String($)}${Q(R)}`);return Q},x=(q,[[z,C,F,H,G],Q,[X,D,E],M])=>{let Y=-1,$=q.parentElement;q.render=()=>{let R=X.findIndex((j)=>j<$.clientWidth);if(R===-1||X[R]===Y)return;let U=z;if(D[R].forEach((j,I)=>{U+=j=="gap"?H:(typeof j=="number"?C.replace(Q,j):F).replace("L<",E?.[R][I]??`${String(j)}<`)}),U+=G,q.innerHTML="",q.insertAdjacentHTML("afterbegin",U),Y=X[R],M&&O)J(q,M)},V.observe($)},w=async(q,[z,C,F])=>{let H=F&&O?await J(q,F):(G)=>G;S(q,(G)=>z.replace(C,H(G)))},A=(q,[z,C,F,H])=>{S(q,(G)=>{return C.replace(F,Math.max(Math.ceil(z/parseInt(G)),1)).replace(H,G)})},S=(q,z)=>{let C=q.querySelector("input"),F=q.querySelector("a"),H=C.value,G=()=>{if(C.value===H)return;let[Q,X,D]=[C.min,C.value,C.max].map((E)=>parseInt(E)||0);if(X<Q||X>D){C.value=H,C.select();return}H=C.value,F.href=z(C.value),F.click()};C.addEventListener("focus",()=>{C.select()}),C.addEventListener("focusout",G),C.addEventListener("keypress",(Q)=>{if(Q.key=="Enter")G()})};return{version:"43.7.0",init(q){let z=q instanceof HTMLElement?q:document,C=z.querySelectorAll("[data-pagy]");for(let F of C)try{let[H,...G]=JSON.parse(T(F.getAttribute("data-pagy")));if(H=="k")J(F,...G);else if(H=="snj")x(F,G);else if(H=="inj")w(F,G);else if(H=="ltj")A(F,G)}catch(H){console.warn(`Pagy.init: %o
2
2
  %s`,F,H)}}}})();
data/javascripts/pagy.mjs CHANGED
@@ -134,7 +134,7 @@ export default (() => {
134
134
  });
135
135
  };
136
136
  return {
137
- version: "43.6.2",
137
+ version: "43.7.0",
138
138
  init(arg) {
139
139
  const target = arg instanceof HTMLElement ? arg : document, elements = target.querySelectorAll("[data-pagy]");
140
140
  for (const element of elements) {
@@ -2,15 +2,31 @@
2
2
 
3
3
  class Pagy
4
4
  module Search
5
- class Arguments < Array
6
- def respond_to_missing?(*) = true
7
-
8
- def method_missing(*) = push(*)
5
+ # Collect the search arguments and record the chained calls, applied later by the paginators.
6
+ # It is not an Array, so methods like filter, reject, sort, etc. get recorded as well
7
+ class Arguments
8
+ def initialize(*arguments)
9
+ @arguments = arguments
10
+ @calls = []
11
+ end
12
+
13
+ # Destructure as [model, arguments, options, block, calls]
14
+ def to_ary = [*@arguments, @calls]
15
+
16
+ # Conversion methods are not recorded
17
+ def respond_to_missing?(name, *) = !name.start_with?('to_')
18
+
19
+ def method_missing(name, *args, **kwargs, &block)
20
+ return super if name.start_with?('to_')
21
+
22
+ @calls << [name, args, kwargs, block]
23
+ self
24
+ end
9
25
  end
10
26
 
11
27
  # Collect the search arguments to pass to the actual search
12
28
  def pagy_search(*arguments, **options, &block)
13
- Arguments.new([self, arguments, options, block])
29
+ Arguments.new(self, arguments, options, block)
14
30
  end
15
31
  end
16
32
 
@@ -20,6 +36,10 @@ class Pagy
20
36
  def search? = true
21
37
  end
22
38
 
39
+ class RailsActiveSearch < SearchBase
40
+ DEFAULT = { search_method: :search }.freeze
41
+ end
42
+
23
43
  class ElasticsearchRails < SearchBase
24
44
  DEFAULT = { search_method: :search,
25
45
  max_result_window: 10_000 }.freeze
@@ -27,13 +27,13 @@ class Pagy
27
27
  end
28
28
 
29
29
  def resolve_limit
30
- default = @options[:limit] || DEFAULT[:limit]
31
- max_limit = @options[:max_limit]
32
- return default unless max_limit
30
+ default = @options[:limit] || DEFAULT[:limit]
31
+ client_limit = @options[:client_limit]
32
+ return default unless client_limit
33
33
 
34
34
  limit_key = @options[:limit_key] || DEFAULT[:limit_key]
35
35
  limit = (@params.dig(@options[:root_key], limit_key) || @params[limit_key]).to_s.to_i
36
- limit.zero? ? default : [limit, max_limit].min
36
+ limit.zero? ? default : [limit, client_limit].min
37
37
  end
38
38
 
39
39
  private
data/lib/pagy/cli.rb CHANGED
@@ -23,7 +23,7 @@ class Pagy
23
23
 
24
24
  parser = OptionParser.new do |opts|
25
25
  opts.banner = <<~BANNER
26
- Pagy #{VERSION} (https://ddnexus.github.io/pagy/playground)
26
+ Pagy #{VERSION} (https://ddnexus.github.io/pagy/sandbox/playground)
27
27
  Playground to showcase, clone and develop Pagy APPs
28
28
 
29
29
  Usage:
@@ -6,9 +6,9 @@
6
6
  class Pagy
7
7
  module Deprecated
8
8
  def self.client_max_limit(options)
9
- if (max_limit = options.delete(:client_max_limit))
10
- options[:max_limit] ||= max_limit
11
- warn '[PAGY] the :client_max_limit option is deprecated: use :max_limit instead.'
9
+ options[:client_limit] ||= options[:max_limit] || options[:client_max_limit]
10
+ %i[max_limit client_max_limit].each do |key|
11
+ warn "[PAGY] the #{key.inspect} option is deprecated: use :client_limit instead." if options.delete(key)
12
12
  end
13
13
  end
14
14
 
@@ -53,7 +53,7 @@ class Pagy
53
53
  end
54
54
 
55
55
  { opts[:page_key] => compose_page_param(page),
56
- opts[:limit_key] => opts[:max_limit] && opts[:limit] }.each do |k, v|
56
+ opts[:limit_key] => opts[:client_limit] && opts[:limit] }.each do |k, v|
57
57
  v ? container[k] = v : container.delete(k)
58
58
  end
59
59
 
@@ -6,15 +6,22 @@ class Pagy
6
6
 
7
7
  # Common search logic
8
8
  def wrap(search_arguments, options)
9
- options[:page] ||= options[:request].resolve_page
10
- options[:limit] = options[:request].resolve_limit
11
-
9
+ resolve(options)
12
10
  pagy, results = yield
11
+ *, calls = search_arguments
12
+
13
+ [pagy, chain(results, calls)]
14
+ end
13
15
 
14
- called = search_arguments[4..]
15
- results = results.send(*called) unless called.empty?
16
+ # Resolve the page and limit from the request
17
+ def resolve(options)
18
+ options[:page] ||= options[:request].resolve_page
19
+ options[:limit] = options[:request].resolve_limit
20
+ end
16
21
 
17
- [pagy, results]
22
+ # Apply the calls recorded by Search::Arguments
23
+ def chain(receiver, calls)
24
+ calls.reduce(receiver) { |object, (name, args, kwargs, block)| object.send(name, *args, **kwargs, &block) }
18
25
  end
19
26
  end
20
27
  end
data/lib/pagy/next.rb CHANGED
@@ -14,7 +14,7 @@ class Pagy
14
14
  module Discontinued
15
15
  # Ensure a discontinued option won't pass unnoticed shadowing a bug
16
16
  def assign_options(**options)
17
- discontinued = options.keys & %i[max_pages client_max_limit]
17
+ discontinued = options.keys & %i[max_pages client_max_limit max_limit]
18
18
  return super if discontinued.empty?
19
19
 
20
20
  raise NextError, "discontinued #{discontinued.map(&:inspect).join(', ')}: " \
@@ -11,7 +11,9 @@ class Pagy
11
11
 
12
12
  # Generate a hash of RFC-8288-compliant http headers
13
13
  def headers_hash(headers_map: @options[:headers_map] || DEFAULT_HEADERS_MAP, **)
14
- links = urls_hash(**, absolute: true).map { %(<#{_2}>; rel="#{_1}") }.join(', ')
14
+ links = urls_hash(**, absolute: true).map do |key, url|
15
+ %(<#{url}>; rel="#{key == :previous ? :prev : key}")
16
+ end.join(', ')
15
17
 
16
18
  headers_map.each_with_object('link' => links) do |(key, name), hash|
17
19
  next unless name
@@ -4,10 +4,10 @@ require_relative 'support/data_pagy_attribute'
4
4
 
5
5
  class Pagy
6
6
  module NumericHelpers
7
- def limit_tag_js(id: nil, item_name: nil, max_limit: @options[:max_limit], **)
8
- raise OptionError.new(self, :max_limit, 'to be truthy', max_limit) unless max_limit
7
+ def limit_tag_js(id: nil, item_name: nil, client_limit: @options[:client_limit], **)
8
+ raise OptionError.new(self, :client_limit, 'to be truthy', client_limit) unless client_limit
9
9
 
10
- limit_input = %(<input name="limit" type="number" min="1" max="#{max_limit}" value="#{
10
+ limit_input = %(<input name="limit" type="number" min="1" max="#{client_limit}" value="#{
11
11
  @limit}" style="padding: 0; text-align: center; width: #{@limit.to_s.length + 1}rem;">#{A_TAG})
12
12
 
13
13
  url_token = compose_page_url(PAGE_TOKEN, limit: LIMIT_TOKEN)
@@ -9,11 +9,11 @@ class Pagy
9
9
  private
10
10
 
11
11
  # The reverse-sorted array of widths, series, and labels generated from the :steps hash.
12
- # If :steps is false it will use the single {0 => @options[:slots]} length
13
- def sequels(steps: @options[:steps] || { 0 => @options[:slots] || SERIES_SLOTS }, **)
12
+ # If :steps is not set it will use the single {0 => slots} step; :compact applies to all the steps
13
+ def sequels(slots: @options[:slots] || SERIES_SLOTS, compact: @options[:compact], steps: @options[:steps] || { 0 => slots }, **)
14
14
  raise OptionError.new(self, :steps, 'to define the 0 width', steps) unless steps.key?(0)
15
15
 
16
- widths, series = steps.sort.reverse.map { |width, slots| [width, series(slots:)] }.transpose
16
+ widths, series = steps.sort.reverse.map { |width, step_slots| [width, series(slots: step_slots, compact:)] }.transpose
17
17
  [widths, series, page_labels(series)]
18
18
  end
19
19
 
@@ -4,9 +4,10 @@ class Pagy
4
4
  def urls_hash(**)
5
5
  template = compose_page_url(PAGE_TOKEN, **)
6
6
 
7
- { first: compose_page_url(nil, **),
8
- previous: @previous && template.sub(PAGE_TOKEN, @previous.to_s),
9
- next: @next && template.sub(PAGE_TOKEN, @next.to_s),
10
- last: @count && template.sub(PAGE_TOKEN, @last.to_s) }.compact
7
+ urls = { first: compose_page_url(nil, **),
8
+ previous: @previous && template.sub(PAGE_TOKEN, @previous.to_s),
9
+ next: @next && template.sub(PAGE_TOKEN, @next.to_s),
10
+ last: @count && template.sub(PAGE_TOKEN, @last.to_s) }.compact
11
+ @options[:jsonapi] ? urls.transform_keys(previous: :prev) : urls # JSON:API requires :prev
11
12
  end
12
13
  end
@@ -11,6 +11,7 @@ class Pagy
11
11
  calendar: :CalendarPaginator,
12
12
  elasticsearch_rails: :ElasticsearchRailsPaginator,
13
13
  meilisearch: :MeilisearchPaginator,
14
+ rails_active_search: :RailsActiveSearchPaginator,
14
15
  searchkick: :SearchkickPaginator,
15
16
  typesense_rails: :TypesenseRailsPaginator }.freeze
16
17
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../modules/searcher'
4
+
5
+ class Pagy
6
+ module RailsActiveSearchPaginator
7
+ module_function
8
+
9
+ def paginate(search, options)
10
+ if search.is_a?(Search::Arguments) # Active mode
11
+ Searcher.resolve(options)
12
+ model, arguments, search_options, block, calls = search
13
+
14
+ method = options[:search_method] || RailsActiveSearch::DEFAULT[:search_method]
15
+ # The chained calls build the ActiveSearch::Query, so they apply before executing it
16
+ query = Searcher.chain(model.send(method, *arguments, **search_options, &block), calls)
17
+ results = query.limit(options[:limit])
18
+ .offset(options[:limit] * (options[:page] - 1))
19
+ .results
20
+ options[:count] = results.total
21
+
22
+ [RailsActiveSearch.new(**options), results]
23
+ else # Passive mode (ActiveSearch::Results)
24
+ # TODO: use the public readers when ActiveSearch::Results will provide them
25
+ limit = search.instance_variable_get(:@limit)
26
+ offset = search.instance_variable_get(:@offset).to_i # nil when not set
27
+ options[:limit] = limit
28
+ options[:page] = (offset / limit) + 1
29
+ options[:count] = search.total
30
+
31
+ RailsActiveSearch.new(**options)
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/pagy.rb CHANGED
@@ -9,7 +9,7 @@ require_relative 'pagy/toolbox/helpers/loaders'
9
9
 
10
10
  # Top superclass
11
11
  class Pagy
12
- VERSION = '43.6.2'
12
+ VERSION = '43.7.0'
13
13
  ROOT = Pathname.new(__dir__).parent.freeze
14
14
  DEFAULT = { limit: 20, limit_key: 'limit', page_key: 'page' }.freeze
15
15
  PAGE_TOKEN = EscapedValue.new('P ')
@@ -24,6 +24,7 @@ class Pagy
24
24
  autoload :Calendar, path.join('classes/calendar/calendar')
25
25
  autoload :Offset, path.join('classes/offset/offset')
26
26
  autoload :Search, path.join('classes/offset/search')
27
+ autoload :RailsActiveSearch, path.join('classes/offset/search')
27
28
  autoload :ElasticsearchRails, path.join('classes/offset/search')
28
29
  autoload :Meilisearch, path.join('classes/offset/search')
29
30
  autoload :Searchkick, path.join('classes/offset/search')
@@ -74,8 +75,8 @@ class Pagy
74
75
  @request = options.delete(:request) # internal object
75
76
  validate_string_values(options)
76
77
 
77
- default = {}
78
- current = self.class
78
+ default = {}
79
+ current = self.class
79
80
 
80
81
  loop do
81
82
  default = current::DEFAULT.merge(default)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pagy
3
3
  version: !ruby/object:Gem::Version
4
- version: 43.6.2
4
+ version: 43.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Domizio Demichelis
@@ -60,6 +60,7 @@ extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
62
  - LICENSE.txt
63
+ - apps/active_search.ru
63
64
  - apps/calendar.ru
64
65
  - apps/demo.ru
65
66
  - apps/enable_rails_page_segment.rb
@@ -153,6 +154,7 @@ files:
153
154
  - lib/pagy/toolbox/paginators/meilisearch.rb
154
155
  - lib/pagy/toolbox/paginators/method.rb
155
156
  - lib/pagy/toolbox/paginators/offset.rb
157
+ - lib/pagy/toolbox/paginators/rails_active_search.rb
156
158
  - lib/pagy/toolbox/paginators/searchkick.rb
157
159
  - lib/pagy/toolbox/paginators/typesense_rails.rb
158
160
  - locales/ar.yml
@@ -220,7 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
220
222
  - !ruby/object:Gem::Version
221
223
  version: '0'
222
224
  requirements: []
223
- rubygems_version: 4.0.16
225
+ rubygems_version: 4.0.20
224
226
  specification_version: 4
225
227
  summary: "Pagy \U0001F438 The Leaping Gem!"
226
228
  test_files: []