picky-generators 4.2.4 → 4.3.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.
@@ -1,60 +1,232 @@
1
1
  !!!
2
2
  %html{ :lang => 'en' }
3
3
  %head
4
- %link{:href => "stylesheets/picky.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}/
5
4
  %link{:href => "stylesheets/application.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}/
6
-
5
+ %link{:href => "stylesheets/picky.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}/
7
6
  = js 'jquery-1.5.0.min'
8
7
  = js 'history.min'
9
8
  = js 'history.adapter.jquery.min'
10
9
  = js 'picky.min'
11
10
 
12
11
  %body
13
- %img{:src => "images/picky.png"}/
14
- %p
15
- %a{:href => "http://florianhanke.com/picky"} To the Picky Homepage
16
- \/
17
- %a{:href => '/configure' } Configuring this app server
18
- %p
19
- Try a few examples
20
- = succeed ":" do
21
- %span.explanation (on a simple database with 540 books - note that the server is on Heroku and needs a little time to ramp up)
22
- %p
23
- A simple word,
24
- = succeed "." do
25
- %a{:href => "#", :onclick => "pickyClient.insert('alan');"} alan
26
- %span.explanation
27
- (Finds Alan in the title, and Alans who wrote books. The title is ranked higher due to weighing.)
28
- %span
29
- %p
30
- With qualifier,
31
- = succeed "." do
32
- %a{:href => "#", :onclick => "pickyClient.insert('title:women');"} title:women
33
- %span.explanation
34
- (Finds "women*" just in titles.)
35
- %span
36
- %p
37
- With similarity,
38
- = succeed "." do
39
- %a{:href => "#", :onclick => "pickyClient.insert('pinchn~');"} pinchn~
40
- %span.explanation (Finds "pynchon", note: Only title in example with similarity. Uses a combination of double metaphone and Levenshtein.)
41
- %p
42
- More complex,
43
- = succeed "." do
44
- %a{:href => "#", :onclick => "pickyClient.insert('title:lyterature~');"} title:lyterature~
45
- %span.explanation (Finds similar titles)
46
- %p
47
- With choice,
48
- = succeed "." do
49
- %a{:href => "#", :onclick => "pickyClient.insert('sp');"} sp
50
- %span.explanation (Finds "sp*" in multiple categories. Choose the one you're looking for.)
51
- %p
52
- More complex,
53
- = succeed "." do
54
- %a{:href => "#", :onclick => "pickyClient.insert('soc* p');"} soc* p
55
- %span.explanation (This is where Picky really shines, "the title started with soc, and the author starts with p")
12
+ %hgroup
13
+ / Replace these headers with your code
14
+ %img{ :class => 'picky', :src => "images/picky.png"}/
15
+ %h1 Picky
16
+ %h2
17
+ Scaffold: A great start into your
18
+ %em fantastic
19
+ search engine!
20
+
21
+ %a{ :href => "http://florianhanke.com/picky" } Picky Homepage
56
22
  .content
57
23
  = Picky::Helper.cached_interface
24
+ %section
25
+ %h1 Examples:
26
+ %p
27
+ %a{:href => "", :onclick => "pickyClient.insert('alan');"} alan
28
+ finds Alan in the title, and Alans who wrote books. The title is ranked higher due to weighing.
29
+ %p
30
+ %a{:href => "", :onclick => "pickyClient.insert('title:women');"} title:women
31
+ finds "women*" just in titles.
32
+ %p
33
+ %a{:href => "", :onclick => "pickyClient.insert('pinchn~');"} pinchn~
34
+ finds the similar "pynchon".
35
+ %p
36
+ %a{:href => "", :onclick => "pickyClient.insert('title:lyterature~');"} title:lyterature~
37
+ finds similar titles.
38
+ %p
39
+ %a{:href => "", :onclick => "pickyClient.insert('sp');"} sp
40
+ finds "sp*" in multiple categories. Choose the one you're looking for.
41
+ %p
42
+ %a{:href => "", :onclick => "pickyClient.insert('soc* p');"} soc* p
43
+ means "find something that starts with soc, and another thing starting with p".
44
+ %section
45
+ %h1 Already made it this far? You're good!
46
+ %p I think you're ready for configuring me for your own purposes.
47
+ %h2 Configuring the Picky client.
48
+ %p
49
+ There are two places where you configure the Picky client:
50
+ %ol
51
+ %li
52
+ %a{ :href => '#controller' } In the controller.
53
+ (client to Picky server)
54
+ %li
55
+ %a{ :href => '#view' } In the view.
56
+ (javascript client interface)
57
+ %h2#controller Controller
58
+ %p
59
+ Open the file
60
+ %strong app.rb
61
+ and take a peek inside.
62
+ %p
63
+ First you need both a client instance for a
64
+ %strong full
65
+ or a
66
+ %strong live search
67
+ depending on what you need (Full gets results with IDs, Live without and is used for updating the counter).
68
+ %p
69
+ In the example, I called it
70
+ %strong BookSearch
71
+ \.
72
+ %code
73
+ %pre
74
+ :preserve
75
+ BookSearch = Picky::Client.new host: 'localhost',
76
+ port: 8080,
77
+ path: '/books'
78
+ %p
79
+ Both clients offer the options:
80
+ %dl
81
+ %dt
82
+ %strong host
83
+ %dd The Picky search server host.
84
+ %dt
85
+ %strong port
86
+ %dd The Picky search server port (see unicorn.rb in the server).
87
+ %dt
88
+ %strong path
89
+ %dd The Picky search path (see app.rb in the server).
90
+ %p
91
+ Then, use these Client instances in your actions. For example like this:
92
+ %code
93
+ %pre
94
+ :preserve
95
+ get '/search/full' do
96
+ results = BookSearch.search params[:query],
97
+ :ids => params[:ids],
98
+ :offset => params[:offset]
99
+ results.extend Picky::Convenience
100
+ results.populate_with Book do |book|
101
+ book.to_s
102
+ end
103
+ ActiveSupport::JSON.encode results
104
+ end
105
+ %p
106
+ This part gets a
107
+ %strong hash
108
+ with the results:
109
+ %code
110
+ %pre
111
+ :preserve
112
+ results = BookSearch.search params[:query],
113
+ :ids => params[:ids],
114
+ :offset => params[:offset]
115
+ %p
116
+ This part takes the
117
+ %strong hash
118
+ and extends it with a few useful and convenient methods:
119
+ %code
120
+ %pre results.extend Picky::Convenience
121
+ %p
122
+ One of these methods is the
123
+ %strong populate_with
124
+ method which takes a
125
+ %strong model
126
+ as parameter, and then gets the corresponding
127
+ %strong model instances
128
+ for each id in the result.
129
+ %code
130
+ %pre
131
+ :preserve
132
+ results.populate_with Book do |book|
133
+ book.to_s
134
+ end
135
+ The
136
+ %strong book.to_s
137
+ simulates rendering a book.
138
+ You can do whatever with the book instance if you just return a rendered thing that's supposed to be shown in the front end.
139
+ %p
140
+ If you don't want to render in the controller, you can do so in a view. In the controller just call
141
+ %code
142
+ %pre
143
+ results.populate_with Book
144
+ and then render the books in a view using:
145
+ %code
146
+ %pre
147
+ :preserve
148
+ results.entries do |book|
149
+ render book # or book.to_s, or however you like to render the book.
150
+ end
151
+ %p
152
+ At the end, encode the hash in JSON:
153
+ %code
154
+ %pre
155
+ ActiveSupport::JSON.encode results
156
+ That's it for the controller.
157
+ %p
158
+ All the steps in one:
159
+ %code
160
+ %pre
161
+ :preserve
162
+ BookSearch = Picky::Client.new host: 'localhost',
163
+ port: 8080,
164
+ path: '/books'
165
+
166
+ get '/search/full' do
167
+ results = BookSearch.search params[:query],
168
+ ids: params[:ids],
169
+ offset: params[:offset]
170
+
171
+ results.extend Picky::Convenience
172
+ results.populate_with Book do |book|
173
+ book.to_s
174
+ end
175
+
176
+ ActiveSupport::JSON.encode results
177
+ end
178
+ %h2#view View
179
+ %p
180
+ The view is even easier. Just add the line
181
+ %code
182
+ %pre
183
+ :preserve
184
+ = Picky::Helper.cached_interface
185
+ if you use just one language, or
186
+ %code
187
+ %pre
188
+ :preserve
189
+ = Picky::Helper.interface button: 'search',
190
+ no_results: 'No results!',
191
+ more: 'more'
192
+ if you use multiple languages.
193
+ (You'd use the options
194
+ %code
195
+ %pre
196
+ :preserve
197
+ button: t(:'search.button'),
198
+ no_results: t(:'search.no_results'),
199
+ more: t(:'search.more')
200
+ of course, with proper i18n)
201
+ The same options can be used for
202
+ %strong #cached_interface
203
+ but they will be cached, so you can only set them once and then reused.
204
+ %p
205
+ You're almost finished. Take a look at the file
206
+ %strong views/search.haml
207
+ where you'll find javascript at the end. It looks something like this:
208
+ %code
209
+ %pre
210
+ :preserve
211
+ :javascript
212
+ pickyClient = new PickyClient({
213
+ // A full query displays the rendered results.
214
+ //
215
+ full: '/search/full',
216
+
217
+ // etc.
218
+ Just take a look at the possible javascript client options in that file.
219
+ %p
220
+ %strong Good luck my friend!
221
+ %em *waves several stubby pink tentacles*
222
+ %footer
223
+ Website design by
224
+ %a{ :href => 'http://twitter.com/thijs' } Thijs van der Vossen
225
+ of
226
+ %a{ :href => 'http://fngtps.com' } Fingertips
227
+ with modifications by
228
+ = succeed('.') do
229
+ %a{ :href => 'http://twitter.com/hanke' } Florian Hanke
58
230
  :javascript
59
231
  $(window).load(function() {
60
232
  pickyClient = new PickyClient({
@@ -63,13 +235,12 @@
63
235
  full: '/search/full',
64
236
  // fullResults: 100, // Optional. Amount of ids to search for, default 20.
65
237
 
66
- // A live query just updates the count and does not need
67
- // to render (could go straight to the search server).
238
+ // A live query just updates the count.
68
239
  //
69
240
  live: '/search/live',
70
241
  // liveResults: 0, // Optional. Amount of ids to search for, default 0.
71
242
 
72
- // showResultsLimit: 10, // Optional. Default is 10.
243
+ // showResultsLimit: 100, // Optional. Default is 10.
73
244
 
74
245
  // Wrap each li group (like author-title, or title-isbn etc.) of results
75
246
  // in this element.
@@ -77,7 +248,7 @@
77
248
  //
78
249
  // wrapResults: '<div class="hello"><ol class="world"></ol></div>',
79
250
 
80
- // before: function(params, query) { }, // Optional. Before Picky sends any data.
251
+ // before: function(query, params) { }, // Optional. Before Picky sends any data. Return modified query.
81
252
  // success: function(data, query) { }, // Optional. Just after Picky receives data. (Get a PickyData object)
82
253
  // after: function(data, query) { }, // Optional. After Picky has handled the data and updated the view.
83
254
 
@@ -103,14 +274,17 @@
103
274
  choices: {
104
275
  en:{
105
276
  'title': {
106
- format: "<strong>%1$s</strong>",
277
+ format: "Called <strong>%1$s</strong>",
107
278
  filter: function(text) { return text.toUpperCase(); },
108
- ignoreSingle: false
279
+ ignoreSingle: true
109
280
  },
110
- 'author,title': '%1$s, who wrote %2$s',
111
- 'title,author': '%2$s, written by %2$s',
112
- 'title,subjects': '%1$s, about %2$s',
113
- 'author,subjects': '%1$s, who wrote about %2$s'
281
+ 'author': 'Written by %1$s',
282
+ 'subjects': 'Being about %1$s',
283
+ 'publisher': 'Published by %1$s',
284
+ 'author,title': 'Called %1$s, written by %2$s',
285
+ 'title,author': 'Called %2$s, written by %1$s',
286
+ 'title,subjects': 'Called %1$s, about %2$s',
287
+ 'author,subjects': '%1$s who wrote about %2$s'
114
288
  }
115
289
  },
116
290
 
@@ -122,9 +296,9 @@
122
296
  en:{
123
297
  title: 'titled',
124
298
  author: 'written by',
125
- year: 'published in'
126
- // publisher: 'published by',
127
- // subjects: 'topics'
299
+ year: 'published in',
300
+ publisher: 'published by',
301
+ subjects: 'with subjects'
128
302
  }
129
303
  }
130
304
  });
@@ -2,22 +2,21 @@ require 'rubygems'
2
2
  require 'bundler'
3
3
  Bundler.require
4
4
 
5
- # Sinatra settings.
5
+ # Load the "model".
6
6
  #
7
- set :static, true
8
- set :public, File.dirname(__FILE__)
9
- set :views, File.expand_path('../views', __FILE__)
10
- set :haml, :format => :html5
7
+ require File.expand_path 'book', File.dirname(__FILE__)
11
8
 
12
- # Load the simplified "model".
13
- #
14
- require File.expand_path '../book', __FILE__
9
+ set :haml, { :format => :html5 }
15
10
 
16
- # Sets up a search instance to the server.
11
+ # Sets up two query instances.
17
12
  #
18
- BookSearch = Picky::Client.new :host => 'localhost', :port => 8080, :path => '/books'
13
+ BooksSearch = Picky::Client.new :host => 'localhost', :port => 8080, :path => '/books'
14
+
15
+ set :static, true
16
+ set :public, File.dirname(__FILE__)
17
+ set :views, File.expand_path('views', File.dirname(__FILE__))
19
18
 
20
- # Root, the search page.
19
+ # Root, the search interface.
21
20
  #
22
21
  get '/' do
23
22
  @query = params[:q]
@@ -25,41 +24,31 @@ get '/' do
25
24
  haml :'/search'
26
25
  end
27
26
 
28
- # Renders the results into the json.
29
- #
30
- # You get the results from the picky server and then
31
- # populate the result hash with rendered models.
27
+ # For full results, you get the ids from the picky server
28
+ # and then populate the result with models (rendered, even).
32
29
  #
33
30
  get '/search/full' do
34
- results = BookSearch.search params[:query], :ids => params[:ids], :offset => params[:offset]
31
+ results = BooksSearch.search params[:query], :ids => params[:ids], :offset => params[:offset]
35
32
  results.extend Picky::Convenience
36
33
  results.populate_with Book do |book|
37
- book.render
34
+ book.to_s
38
35
  end
39
36
 
40
37
  #
41
- # Or, to populate with the model instances, use:
38
+ # Or use:
42
39
  # results.populate_with Book
43
40
  #
44
- # Then to render:
41
+ # Then:
45
42
  # rendered_entries = results.entries.map do |book| (render each book here) end
46
43
  #
47
44
 
48
- Yajl::Encoder.encode results
45
+ ActiveSupport::JSON.encode results
49
46
  end
50
47
 
51
- # Updates the search count while the user is typing.
52
- #
53
- # We don't parse/reencode the returned json string using search_unparsed.
48
+ # For live results, you'd actually go directly to the search server without taking the detour.
54
49
  #
55
50
  get '/search/live' do
56
- BookSearch.search_unparsed params[:query], :ids => params[:ids], :offset => params[:offset]
57
- end
58
-
59
- # Configure. The configuration info page.
60
- #
61
- get '/configure' do
62
- haml :'/configure'
51
+ BooksSearch.search_unparsed params[:query], :offset => params[:offset]
63
52
  end
64
53
 
65
54
  helpers do
@@ -9,34 +9,34 @@ require 'csv'
9
9
  # * a number of subjects
10
10
  #
11
11
  class Book
12
-
12
+
13
13
  @@books_mapping = {}
14
-
14
+
15
15
  # Load the books on startup.
16
16
  #
17
17
  file_name = File.expand_path 'library.csv', File.dirname(__FILE__)
18
18
  CSV.open(file_name, 'r').each do |row|
19
19
  @@books_mapping[row.shift.to_i] = row
20
20
  end
21
-
21
+
22
22
  # Find uses a lookup table.
23
23
  #
24
24
  def self.find ids, _ = {}
25
25
  ids.map { |id| new(id, *@@books_mapping[id]) }
26
26
  end
27
-
27
+
28
28
  attr_reader :id
29
-
29
+
30
30
  def initialize id, title, author, year, publisher, subjects
31
31
  @id, @title, @author, @year, @publisher, @subjects = id, title, author, year, publisher, subjects
32
32
  end
33
-
33
+
34
34
  # "Rendering" ;)
35
35
  #
36
36
  # Note: This is just an example. Please do not render in the model.
37
37
  #
38
- def render
39
- "<li class='book'><p>\"#{@title}\", by #{@author}</p><p>#{@year}, #{@publisher}</p><p>#{@subjects}</p></li>"
38
+ def to_s
39
+ "<li class='book'><h3><a href='http://google.com?q=#{@title}'>#{@title}</a></h3><em>#{@author}</em><p>#{@year}, #{@publisher}</p><p>#{@subjects}</p></li>"
40
40
  end
41
-
41
+
42
42
  end
@@ -1,17 +1,19 @@
1
- Array.prototype.index=function(b){for(var e=0,g=this.length;e<g;e++)if(this[e]==b)return e;return null};Array.prototype.include=function(b){return this.index(b)!==null};Array.prototype.remove=function(b){this.splice(b,1);return this};Array.prototype.compare=function(b){return this.join("")==b.join("")};Array.prototype.each=function(b){for(var e=0,g=this.length;e<g;e++)b(e,this[e]);return this};var PickyI18n={};$(function(){PickyI18n.locale=$("html").attr("lang").split("-")[0]||"en"});
2
- var dictionary={common:{join:{de:"und",fr:"et",it:"e",en:"and",ch:"und"},"with":{de:"mit",fr:"avec",it:"con",en:"with",ch:"mit"},of:{de:"von",fr:"de",it:"di",en:"of",ch:"vo"},to:{de:"bis",fr:"\u00e0",it:"alla",en:"to",ch:"bis"}},results:{addination:{more:{de:"Weitere Resultate",fr:"Autres r\u00e9sultats",it:"Altri risultati",en:"More results",ch:"Mee Resultaat"}},header:{de:"Ergebnisse",fr:"R\u00e9sultats",it:"Risultati",en:"Results",ch:"Erg\u00e4bnis"}}},t=function(b){for(var e=PickyI18n.locale||
3
- "en",g=b.split(".").concat(e),f=dictionary,d=0,k=g.length;d<k;d++){f=f[g[d]];if(f==undefined){f="Translation missing: "+b+"."+e;break}}return f};function Allocation(b,e,g,f,d,k){var n=this;this.type=b;this.weight=e;this.count=g;this.combination=f;this.ids=d||[];this.entries=this.rendered=k||[];this.isType=function(r){return r==n.type}}function Allocations(b){this.allocations=[];for(var e=0,g=b.length;e<g;e++){var f=b[e];this.allocations.push(new Allocation(f[0],f[1],f[2],f[3],f[4],f[5]))}this.length=this.allocations.length;this.each=function(d){return this.allocations.each(d)}}
4
- function PickyData(b){var e=b.total,g=b.duration,f=b.offset,d=new Allocations(b.allocations||[]);this.original_hash=b;this.total=e;this.duration=g;this.offset=f;this.allocations=d;this.renderedAmount=function(){var k=0;d.each(function(n,r){k+=r.rendered.length});return k};this.isEmpty=function(){return e==0}};var PickyView=function(b,e){var g=e.showResultsLimit||10,f=$(e.inputSelector||"#picky input.query"),d=$(e.resetSelector||"#picky div.reset"),k=$(e.buttonSelector||"#picky input.search_button"),n=$(e.counterSelector||"#picky div.status"),r=$(e.dashboardSelector||"#picky .dashboard"),u=$(e.resultsSelector||"#picky div.results"),s=$(e.noResultsSelector||"#picky .no_results"),i=new PickyAddination(this,u),o=new PickyAllocationsCloud(this,e),p=new PickyResultsRenderer(i,e),a=function(){d.fadeTo(166,1)},
5
- c=function(){o.hide();u.empty();s.hide()},h=function(j){f.val(j);d.fadeTo(166,0);v("empty");n.empty();c()},m=function(){return f.val()};this.text=m;var q=function(j){n.text(j);j>0&&j<=5&&n.fadeTo("fast",0.5).fadeTo("fast",1)},w=function(j){if(j.isEmpty())return"none";if(j.total>g&&j.allocations.length>1)return"support";return"ok"},v=function(j){r.attr("class","dashboard "+j)};this.insert=function(j){f.val(j);f.select()};this.fullResultsCallback=function(j){v(w(j));if(j.isEmpty()){c();q(0);s.show();
6
- a()}else if(j.total>g&&j.allocations.length>1){c();a();o.show(j);q(j.total)}else if(j.offset==0){c();q(j.total);p.render(j);u.show();a();f.focus()}else{var y=$("#picky div.results div.addination:last").position().top;i.remove();p.render(j);$("body").animate({scrollTop:y-12},500)}};this.liveResultsCallback=function(j){v(w(j));q(j.total)};this.allocationChosen=function(j){j=j.data.query;f.val(j);b.allocationChosen(j)};this.addinationClicked=function(j){b.addinationClicked(m(),j)};(function(){f.keyup(function(j){if(m()==
7
- ""){h();b.searchTextCleared()}else{b.searchTextEntered(m(),j);a()}});n.click(function(){m()==""||b.searchButtonClicked(m())});k.click(function(){m()==""||b.searchButtonClicked(m())});d.click(function(){h("");b.clearButtonClicked();f.focus()})})();f.focus()};var PickyBackend=function(b){var e=function(g,f,d){var k=d||{};k=$.extend({query:g},d);$.getJSON(b,k,function(n){f&&f(new PickyData(n))})};this.search=function(g,f,d,k){e(g,function(n){f&&f(k,n)},d)}},LiveBackend=function(b){var e=b.live||alert("A live backend path must be provided."),g=new PickyBackend(e);this.search=function(f,d,k,n){n=n||{};latestRequestTimestamp=new Date;n.live=latestRequestTimestamp;k=$.extend({ids:b.liveResults||0,offset:0},k);g.search(f,function(r,u){if(!r.live||r.live==latestRequestTimestamp)d&&
8
- d(u)},k,n)}},FullBackend=function(b){var e=b.full||alert("A full backend path must be provided."),g=new PickyBackend(e);this.search=function(f,d,k,n){n=n||{};latestRequestTimestamp=new Date;n.full=latestRequestTimestamp;k=$.extend({ids:b.fullResults||20,offset:0},k);g.search(f,function(r,u){if(!r.full||r.full==latestRequestTimestamp)d&&d(u)},k,n)}};var PickyController=function(b){var e=new PickyView(this,b),g=b.backends,f=b.before||function(){},d=b.success||function(){},k=b.after||function(){},n=function(a){return(a=a&&a.match(/q=([^&]+)/))&&unescape(a[1]||"")};this.extractQuery=n;var r=function(){var a=window.History&&window.History.getState();return n(a&&a.url)};this.lastQuery=r;var u=function(a,c){a=d(a,c)||a;e.liveResultsCallback(a);k(a,c)},s,i=function(){var a=e.text(),c={};a=f(a,c)||a;var h=g.live;h&&h.search(a,u,c);clearInterval(s)};
9
- s=setInterval(i,180);clearInterval(s);var o=function(a,c){a=d(a,c)||a;e.fullResultsCallback(a);k(a,c)},p=function(a,c){var h=c||{};clearInterval(s);if(a!=r()){var m="?q="+escape(a).replace(/\*/g,"%2A");window.History&&window.History.getState()&&window.History.pushState&&window.History.pushState(null,null,m)}a=f(a,h)||a;(m=g.full)&&m.search(a,o,h)};this.insert=function(a,c,h){e.insert(a);h&&p(a,c)};this.clearButtonClicked=function(){clearInterval(s)};this.searchTextCleared=function(){clearInterval(s)};
10
- this.searchTextEntered=function(a,c){if($.inArray(c.keyCode,[0,8,13,32,46,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90])>-1)if(c.keyCode==13)p(a);else{clearInterval(s);s=setInterval(i,180)}};this.searchButtonClicked=function(a){p(a)};this.allocationChosen=function(a){p(a)};this.addinationClicked=function(a,c){p(a,{offset:c.data.offset})}};var Localization={},PickyClient=function(b){Localization.qualifiers=b.qualifiers||{};Localization.explanations=b.explanations||{};Localization.choices=b.choices||{};Localization.explanation_delimiters={de:"und",fr:"et",it:"e",en:"and",ch:"und"};var e=b.backends;if(e){e.live||alert("Both a full and live backend must be provided.");e.full||alert("Both a full and live backend must be provided.")}else b.backends={live:new LiveBackend(b),full:new FullBackend(b)};var g=b.controller&&new b.controller(b)||
11
- new PickyController(b);var f=this.insert=function(d,k,n){g.insert(d,k||{},n||true)};this.insertFromURL=function(d){if(d&&d!="")f(d);else(d=g.lastQuery())&&f(d)};window.History&&window.History.Adapter.bind(window,"statechange",function(){var d=window.History.getState();(d=g.extractQuery(d.url))&&f(d)})};var PickyAddination=function(b,e){this.remove=function(){e.find(".addination").remove()};this.render=function(g){var f=g.total,d,k=g.renderedAmount();d=g.offset+k;k=d+k;g=g.total;if(g<k)k=g;d={offset:d,start:d+1,end:k};if(d.offset<f){f=$("<div class='addination'>"+t("results.addination.more")+"</div>");f.bind("click",{offset:d.offset},b.addinationClicked);return f}else return""}};var PickyResultsRenderer=function(b,e){var g=$(e.resultsSelector||"#picky div.results"),f=e.wrapResults||'<ol class="results"></ol>',d=["street_number","zipcode"],k=function(i){var o=i[i.length-1];i=i.slice(0,i.length-1);if(i==[])i=[i];if(!d.include(o[0]))if(o[1].match(/[^\*~]$/))o[1]+="*";i.push(o);return i},n=function(i){for(var o=Localization.explanations&&Localization.explanations[PickyI18n.locale]||{},p=[],a,c=0,h=i.length;c<h;c++){a=i[c];var m=a[0];m=o[m]||m;p.push([m,a[1]])}return p},r=function(i,
12
- o){return[i.replace(/([\w\s\u00c4\u00e4\u00d6\u00f6\u00dc\u00fc\u00e9\u00e8\u00e0]+)/,"<strong>$1</strong>"),o].join(" ")},u=function(i,o){var p=Localization.explanation_delimiters[PickyI18n.locale],a=n(k(o)),c="",h=[];a=$.map(a,function(m){var q=m[0];m=m[1];if(c==""||q==c){m=m.replace(/[\w,]+:(.+)/,"$1");h.push(m);c=q}else{var w=r(c,h.join(" "));h=[];h.push(m);c=q;return w}});a.push(r(c,h.join(" ")));a=a.join(" "+p+" ");return'<span class="explanation">'+i+" "+a+"</span>"},s=function(i,o){var p=
13
- '<div class="header">';p+=u(o.type,o.combination);if(i.offset>0)p+='<div class="tothetop"><a href="#" onclick="javascript:$(\'body\').animate({scrollTop: 0}, 500);">&uarr;</a></div>';return p};this.render=function(i){i.allocations.each(function(o,p){if(p.entries.length>0){g.append(s(i,p)).append(p.entries.join(""));g.children("li").wrapAll(f)}});g.append(b.render(i))}};function AllocationRenderer(b,e){function g(a){var c={},h={},m=[],q;q=0;for(l=a.length;q<l;q++){var w=a[q][0];if(w in c){c[w]=c[w]+" "+a[q][1];m.push(q)}else{c[w]=a[q][1];h[q]=w}}for(q in h)a[q][1]=c[h[q]];for(q=m.length-1;q>=0;q--)a.remove(m[q]);return a}function f(a){return $.map(a,function(c,h){return"%"+(h+1)+"$s"}).join(" ")}function d(a){if(a.length==0)return"";var c=a=g(a);c.sort(function(x,z){return x[0]<z[0]?-1:1});for(var h=[],m=0,q=c.length;m<q;m++)h.push(c[m][0]);var w=h.length==1,v=o[h]||
14
- (o[h]=f(h));if($.type(v)==="string"){o[h]={format:v};v=o[h]}var j=1,y=v.format;$.each(a,function(x,z){var A=z[0],B=z[2];if(v.filter)B=v.filter(B);A=s[A]||A;if(w&&!(v&&v.ignoreSingle))return y=B+"&nbsp;("+A+")";y=y.replace(RegExp("%"+j+"\\$s","g"),B);j+=1;return j});return y}function k(a){for(var c=[],h=0,m=i.length;h<m;h++)c.push([]);c.push([]);h=0;for(m=a.length;h<m;h++){for(var q=a[h],w=q[0],v=false,j=0,y=i.length;j<y;j++)if(i[j].include(w)){c[j].push(q);v=true;break}v||c[c.length-1].push(q)}var x;
15
- for(a=c.length-1;a>=0;a--){x=c[a];if(x.length>0)break}x=x[x.length-1];p.include(x[0])||(x[1]+="...");return $.map(c,function(z){return d(z)})}function n(a){var c=[],h,m;for(m in a){h=a[m][0];h=u[h]||h;c[m]=h+":"+a[m][2]}return c.join(" ")}var r=PickyI18n.locale,u=Localization.qualifiers&&Localization.qualifiers[r]||{},s=Localization.explanations&&Localization.explanations[r]||{},i=e.groups||[],o=Localization.choices&&Localization.choices[r]||{};this.explanation=this.query=this.text="";var p=["street_number",
16
- "zipcode"];this.contract=g;this.rendered=d;this.groupify=k;this.querify=n;this.render=function(a){var c=a.combination,h=a.count;a=n(c);c=k(c).join(" ");c=$('<li><div class="text">'+c+'</div><div class="count">'+h+"</div></li>");c.bind("click",{query:a},b);return c}};var PickyAllocationsCloud=function(b,e){var g=$(e.allocationsSelector||"#picky .allocations"),f=g.find(".shown"),d=g.find(".more"),k=g.find(".hidden"),n=function(){g.hide()},r=new AllocationRenderer(function(i){n();b.allocationChosen(i)},e),u=function(i){var o=[];i.each(function(p,a){o.push(r.render(a))});return o},s=function(i){if(i.length==0)return $("#search .allocations").hide();f.empty();d.hide();k.empty().hide();if(i.length>3){$.each(i.slice(0,2),function(o,p){f.append(p)});$.each(i.slice(2),
17
- function(o,p){k.append(p)});d.show()}else $.each(i,function(o,p){f.append(p)});return $("#search .allocations").show()};d.click(function(){d.hide();k.show()});this.hide=n;this.show=function(i){s(u(i.allocations));g.show()}};
1
+ Array.prototype.index=function(a){for(var b=0,j=this.length;b<j;b++)if(this[b]==a)return b;return null};Array.prototype.include=function(a){return this.index(a)!==null};Array.prototype.remove=function(a){this.splice(a,1);return this};Array.prototype.compare=function(a){return this.join("")==a.join("")};Array.prototype.each=function(a){for(var b=0,j=this.length;b<j;b++)a(b,this[b]);return this};Array.prototype.map=function(a){for(var b=0,j=this.length;b<j;b++)this[b]=a(b,this[b]);return this};var dictionary={common:{join:{de:"und",fr:"et",it:"e",en:"and",ch:"und"},"with":{de:"mit",fr:"avec",it:"con",en:"with",ch:"mit"},of:{de:"von",fr:"de",it:"di",en:"of",ch:"vo"},to:{de:"bis",fr:"\u00e0",it:"alla",en:"to",ch:"bis"}},results:{addination:{more:{de:"Weitere Resultate",fr:"Autres r\u00e9sultats",it:"Altri risultati",en:"More results",ch:"Mee Resultaat"}},header:{de:"Ergebnisse",fr:"R\u00e9sultats",it:"Risultati",en:"Results",ch:"Erg\u00e4bnis"}}},t=function(a){for(var b=PickyI18n.locale||
2
+ "en",j=a.split(".").concat(b),i=dictionary,k=0,n=j.length;k<n;k++){i=i[j[k]];if(i==undefined){i="Translation missing: "+a+"."+b;break}}return i};function Allocation(a,b,j,i,k,n){var p=this;this.type=a;this.weight=b;this.count=j;this.combination=i;this.ids=k||[];this.entries=this.rendered=n||[];this.isType=function(s){return s==p.type}}function Allocations(a){this.allocations=[];for(var b=0,j=a.length;b<j;b++){var i=a[b];this.allocations.push(new Allocation(i[0],i[1],i[2],i[3],i[4],i[5]))}this.length=this.allocations.length;this.remove=function(k){this.allocations.splice(k,1)};this.each=function(k){this.allocations.each(k)}}
3
+ function PickyData(a){var b=a.total,j=a.duration,i=a.offset,k=new Allocations(a.allocations||[]);this.original_hash=a;this.total=b;this.duration=j;this.offset=i;this.allocations=k;this.renderedAmount=function(){var n=0;k.each(function(p,s){n+=s.rendered.length});return n};this.isEmpty=function(){return b==0}};var PickyView=function(a,b){var j=b.showResultsLimit||10,i=b.input,k=b.reset,n=b.button,p=b.counter,s=b.form,x=b.moreSelector,u=b.results,v=b.noResults,z=new PickyAddination(this,u),f=new PickyAllocationsCloud(this,b),d=new PickyResultsRenderer(z,b),g=function(){k.fadeTo(166,1)},o=function(){f.hide();u.empty();v.hide()},m=function(c){i.val(c);k.fadeTo(166,0);s.attr("class","empty");p.empty();o()};this.reset=m;var h=function(){return i.val()};this.text=h;var q=function(c){p.text(c);c>0&&c<=5&&p.fadeTo("fast",
4
+ 0.5).fadeTo("fast",1)},e=function(c){if(c.isEmpty())return"none";if(c.total>j&&c.allocations.length>1)return"support";return"ok"};this.insert=function(c){i.val(c);i.select()};this.fullResultsCallback=function(c){var r=e(c);s.attr("class",r);if(c.isEmpty()){o();q(0);v.show();g()}else if(c.total>j&&c.allocations.length>1){o();g();f.show(c);q(c.total)}else if(c.offset==0){o();q(c.total);d.render(u,c);u.show();g();i.focus()}else{r=$(x).position().top;z.remove();d.render(u,c);$("body").animate({scrollTop:r-
5
+ 12},500)}};this.liveResultsCallback=function(c){var r=e(c);s.attr("class",r);q(c.total)};this.allocationChosen=function(c){c=c.data.query;a.insert(c);a.allocationChosen(c)};this.addinationClicked=function(c){a.addinationClicked(h(),c)};(function(){i.keyup(function(c){if(h()==""){m();a.searchTextCleared()}else g();a.searchTextEntered(h(),c)});p.click(function(){a.searchButtonClicked(h())});n.click(function(){a.searchButtonClicked(h())});k.click(function(){m();a.clearButtonClicked();i.focus()})})();
6
+ i.focus()};var PickyBackend=function(a){var b=function(j,i,k){var n=k||{};n=$.extend({query:j},k);$.getJSON(a,n,function(p){i&&i(new PickyData(p))})};this.search=function(j,i,k,n){b(j,function(p){i&&i(n,p)},k)}},LiveBackend=function(a){var b=a.live||alert("A live backend path must be provided."),j=new PickyBackend(b);this.search=function(i,k,n,p){p=p||{};latestRequestTimestamp=new Date;p.live=latestRequestTimestamp;n=$.extend({ids:a.liveResults||0,offset:0},n);j.search(i,function(s,x){if(!s.live||s.live==latestRequestTimestamp)k&&
7
+ k(x)},n,p)}},FullBackend=function(a){var b=a.full||alert("A full backend path must be provided."),j=new PickyBackend(b);this.search=function(i,k,n,p){p=p||{};latestRequestTimestamp=new Date;p.full=latestRequestTimestamp;n=$.extend({ids:a.fullResults||20,offset:0},n);j.search(i,function(s,x){if(!s.full||s.full==latestRequestTimestamp)k&&k(x)},n,p)}};var PickyController=function(a){var b=new PickyView(this,a),j=a.backends,i=a.beforeInsert||function(){},k=a.before||function(){},n=a.success||function(){},p=a.after||function(){},s=a.liveRendered||false,x=a.liveSearchInterval||180,u,v=function(e){return(e=e&&e.match(/q=([^&]+)/))&&decodeURIComponent(e[1]).replace(/\+/g," ").replace(/#/g,"")||""};this.extractQuery=v;var z=function(){var e=window.History&&window.History.getState();return v(e&&e.url)};this.lastFullQuery=z;var f=function(e,c,r,y){var w=
8
+ k(c,y);if(w!=undefined)c=w;u=[e,c,r,y];w=c;if(w!=z()){w=w==""?"":"?q="+escape(w).replace(/\*/g,"%2A");window.History&&window.History.getState()&&window.History.pushState&&window.History.pushState(null,null,w)}if(c=="")b.reset();else(e=j[e])&&e.search(c,r,y)};this.resend=function(){u&&f.apply(this,u)};var d=function(e,c){e=n(e,c)||e;b.fullResultsCallback(e);p(e,c)},g=function(e,c){clearInterval(m);f("full",e,d,c||{})};a=function(e,c){e=n(e,c)||e;b.liveResultsCallback(e);p(e,c)};var o=s?d:a,m,h=function(){var e=
9
+ b.text();f("live",e,o,{});clearInterval(m)};m=setInterval(h,x);clearInterval(m);var q=function(e,c,r){var y=i(e);if(y!=undefined)e=y;b.insert(e);r&&g(e,c)};this.insert=q;this.clearButtonClicked=function(){clearInterval(m)};this.searchTextCleared=function(){clearInterval(m)};this.searchTextEntered=function(e,c){if($.inArray(c.keyCode,[0,8,13,32,46,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90])>-1)if(c.keyCode==13)g(e);else{clearInterval(m);
10
+ m=setInterval(h,x)}};this.searchButtonClicked=function(e){g(e)};this.allocationChosen=function(e){g(e)};this.addinationClicked=function(e,c){g(e,{offset:c.data.offset})};window.History&&window.History.Adapter.bind(window,"statechange",function(){var e=window.History.getState();e=v(e.url);e!=undefined&&e!=(u&&u.length>1&&u[1])&&q(e,{},true)})};var PickyI18n={},PickyClient=function(a){PickyI18n.locale=$("html").attr("lang").split("-")[0]||"en";a.locale=a.locale||PickyI18n.locale;a.qualifiers=a.qualifiers||{};a.explanations=a.explanations||{};a.choices=a.choices||{};a.explanation_delimiters={ch:"und",de:"und",en:"and",fr:"et",it:"e"};var b=a.backends;if(b){b.live||alert("Both a full and live backend must be provided.");b.full||alert("Both a full and live backend must be provided.")}else a.backends={live:new LiveBackend(a),full:new FullBackend(a)};
11
+ b=a.enclosingSelector||".picky";var j=a.formSelector||b+" form";a.form=$(j);a.input=$(a.inputSelector||j+" input[type=search]");a.reset=$(a.resetSelector||j+" div.reset");a.button=$(a.buttonSelector||j+" input[type=button]");a.counter=$(a.counterSelector||j+" div.status");a.results=$(a.resultsSelector||b+" div.results");a.noResults=$(a.noResultsSelector||b+" div.no_results");a.moreSelector=a.moreSelector||b+" div.results div.addination:last";a.allocations=$(a.allocationsSelector||b+" .allocations");
12
+ a.shownAllocations=a.allocations.find(".shown");a.showMoreAllocations=a.allocations.find(".more");a.hiddenAllocations=a.allocations.find(".hidden");a.maxSuggestions=a.maxSuggestions||3;a.results=$(a.resultsSelector||b+" div.results");a.resultsDivider=a.resultsDivider||"";a.nonPartial=a.nonPartial||[];a.wrapResults=a.wrapResults||"<ol></ol>";var i=a.controller&&new a.controller(a)||new PickyController(a);var k=this.insert=function(n,p,s){i.insert(n,p||{},s||true)};this.resend=i.resend;this.insertFromURL=
13
+ function(n){if(n)k(n);else(n=i.lastFullQuery())&&k(n)}};var PickyAddination=function(a,b){this.remove=function(){b.find(".addination").remove()};this.render=function(j){var i=j.total,k,n=j.renderedAmount();k=j.offset+n;n=k+n;j=j.total;if(j<n)n=j;k={offset:k,start:k+1,end:n};if(k.offset<i){i=$("<div class='addination'>"+t("results.addination.more")+"</div>");i.bind("click",{offset:k.offset},a.addinationClicked);return i}else return""}};var PickyResultsRenderer=function(a,b){var j=b.locale,i=b.explanations||{},k=b.explanation_delimiters||{},n=b.resultsDivider,p=b.wrapResults,s=b.nonPartial,x=function(d){var g=d[d.length-1];if(g===undefined)return[];d=d.slice(0,d.length-1);if(d==[])d=[d];if(!s.include(g[0]))if(g[1].match(/[^\*~]$/))g[1]+="*";d.push(g);return d};this.asteriskifyLastToken=x;var u=function(d){for(var g=i[j]||{},o=[],m,h=0,q=d.length;h<q;h++){m=d[h];var e=m[0];e=g[e]||e;o.push([e,m[1]])}return o};this.explainCategory=
14
+ u;var v=function(d,g){return[d.replace(/([\w\s\u00c4\u00e4\u00d6\u00f6\u00dc\u00fc\u00e9\u00e8\u00e0\,]+)/,"<strong>$1</strong>"),g].join(" ")};this.strongify=v;var z=function(d,g){var o=k[j],m="",h=[],q=[];u(x(g)).each(function(e,c){var r=c[0],y=c[1];y=y.replace(/[\w,]+:(.+)/,"$1");if(m==""||r==m){h.push(y);m=r}else{var w=v(m,h.join(" "));h=[];h.push(y);m=r;q.push(w)}});q.push(v(m,h.join(" ")));q=q.join(" "+o+" ");return q='<span class="explanation">'+d+" "+q+"</span>"};this.explain=z;var f=function(d,
15
+ g){var o='<div class="header">';o+=z(g.type,g.combination);if(d.offset>0)o+='<div class="tothetop"><a href="#" onclick="javascript:$(\'body\').animate({scrollTop: 0}, 500);">&uarr;</a></div>';o+="</div>";return o};this.renderHeader=f;this.render=function(d,g){g.allocations.each(function(o,m){if(m.entries.length>0){d.append(f(g,m)).append(m.entries.join(n));d.children("li").wrapAll(p)}});d.append(a.render(g))}};function AllocationRenderer(a){function b(f){var d={},g={},o={},m=[],h;h=0;for(l=f.length;h<l;h++){var q=f[h][0];if(q in d){d[q].push(f[h][1]);g[q].push(f[h][2]);m.push(h)}else{d[q]=[f[h][1]];g[q]=[f[h][2]];o[h]=q}}for(h in o){f[h][1]=d[o[h]];f[h][2]=g[o[h]]}for(h=m.length-1;h>=0;h--)f.remove(m[h]);return f}function j(f){f.map(function(d){return"%"+(d+1)+"$s"});return f.join(" ")}function i(f){if(f.length==0)return"";f=b(f);f.sort(function(e,c){return e[0]<c[0]?-1:1});for(var d=[],g=0,o=f.length;g<
16
+ o;g++)d.push(f[g][0]);var m=d.length==1,h=v[d.join(",")];if(h===undefined)h=v[d]=j(d);if(typeof h==="string"){v[d]={format:h,ignoreSingle:true};h=v[d]}var q=h.format;f.each(function(e,c){var r=c[0],y=c[1],w=c[2];w.map(function(B,A){var C=y[B];if(C.charAt(C.length-1)=="*")A+="...";return A});h.filter&&w.map(function(B,A){return h.filter(A)});if(m&&!(h&&h.ignoreSingle)){r=x[r]||r;return q=w.join("&nbsp;")+"&nbsp;("+r+")"}w.map(function(B,A){return A.replace(/[\w,]+:(.+)/,"$1")});q=q.replace(RegExp("%"+
17
+ (e+1)+"\\$s","g"),w.join("&nbsp;"))});return q}function k(f){for(var d=[],g=0,o=u.length;g<o;g++)d.push([]);d.push([]);g=0;for(o=f.length;g<o;g++){for(var m=f[g],h=m[0],q=false,e=0,c=u.length;e<c;e++)if(u[e].include(h)){d[e].push(m);q=true;break}q||d[d.length-1].push(m)}var r;for(f=d.length-1;f>=0;f--){r=d[f];if(r.length>0)break}r=r[r.length-1];z.include(r[0])||(r[1]=r[1].valueOf()+"*");return d}function n(f){var d=[];k(f).each(function(g,o){var m=i(o);m&&d.push(m)});return d.join(" ")}var p=a.locale,
18
+ s=a.qualifiers&&a.qualifiers[p]||{},x=a.explanations&&a.explanations[p]||{},u=a.groups||[],v=a.choices&&a.choices[p]||{},z=a.nonPartial||[];this.explanation=this.query=this.text="";this.contract=b;this.makeUpMissingFormat=j;this.rendered=i;this.groupify=k;this.querify=function(f){var d=[],g,o,m;for(m in f){g=f[m][0];g=s[g]||g;o=(o=f[m][1])||"";o=o.charAt(o.length-1)=="*"?"*":"";d[m]=g+":"+f[m][2]+o}return d.join(" ")};this.suggestify=n;this.render=function(f){return n(f.combination)}};var PickyAllocationsCloud=function(a,b){var j=b.allocations,i=b.shownAllocations,k=b.showMoreAllocations,n=b.hiddenAllocations,p=b.maxSuggestions,s=function(){j.hide()},x=function(f){s();a.allocationChosen(f)},u=new AllocationRenderer(b),v=function(f){var d=[];f.each(function(g,o){var m=u.querify(o.combination),h=u.render(o);h=$('<li><div class="text">'+h+'</div><div class="count">'+o.count+"</div></li>");h.bind("click",{query:m},x);d.push(h)});return d},z=function(f){if(f.length==0)return j.hide();
19
+ i.empty();k.hide();n.empty().hide();if(f.length>p){$.each(f.slice(0,p-1),function(d,g){i.append(g)});$.each(f.slice(p-1),function(d,g){n.append(g)});k.show()}else $.each(f,function(d,g){i.append(g)});return j.show()};k.click(function(){k.hide();n.show()});this.hide=s;this.show=function(f){z(v(f.allocations));j.show()}};