picky-generators 4.2.4 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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()}};