cineworld_uk 2.1.6 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -3
  3. data/README.md +56 -14
  4. data/Rakefile +57 -1
  5. data/cineworld_uk.gemspec +1 -2
  6. data/lib/cineworld_uk/cinema.rb +113 -182
  7. data/lib/cineworld_uk/internal/api_response.rb +74 -0
  8. data/lib/cineworld_uk/internal/parser/api/cinema_address.rb +81 -0
  9. data/lib/cineworld_uk/internal/parser/api/film.rb +46 -0
  10. data/lib/cineworld_uk/internal/parser/api/film_lookup.rb +38 -0
  11. data/lib/cineworld_uk/internal/parser/api/performance.rb +46 -0
  12. data/lib/cineworld_uk/internal/parser/api/performances_by_day.rb +50 -0
  13. data/lib/cineworld_uk/internal/title_sanitizer.rb +56 -52
  14. data/lib/cineworld_uk/performance.rb +78 -0
  15. data/lib/cineworld_uk/version.rb +2 -2
  16. data/lib/cineworld_uk.rb +11 -8
  17. data/test/fixtures/api/cinema-detail-10.json +1 -0
  18. data/test/fixtures/api/cinema-detail-21.json +1 -0
  19. data/test/fixtures/api/cinema-detail-3.json +1 -0
  20. data/test/fixtures/api/cinema-detail-96.json +1 -0
  21. data/test/fixtures/api/cinema-list.json +1 -0
  22. data/test/fixtures/api/dates-3.json +1 -0
  23. data/test/fixtures/api/film-list-comingsoon.json +1 -0
  24. data/test/fixtures/api/film-list.json +1 -0
  25. data/test/fixtures/api/performances-tomorrow-3.json +1 -0
  26. data/test/lib/cineworld_uk/cinema_test.rb +96 -197
  27. data/test/lib/cineworld_uk/internal/api_response_test.rb +85 -0
  28. data/test/lib/cineworld_uk/internal/parser/api/cinema_address_test.rb +93 -0
  29. data/test/lib/cineworld_uk/internal/parser/api/film_lookup_test.rb +30 -0
  30. data/test/lib/cineworld_uk/internal/parser/api/film_test.rb +169 -0
  31. data/test/lib/cineworld_uk/internal/parser/api/performance_test.rb +62 -0
  32. data/test/lib/cineworld_uk/internal/title_sanitizer_test.rb +1 -1
  33. data/test/lib/cineworld_uk/{screening_test.rb → performance_test.rb} +36 -48
  34. data/test/support/fixture_reader.rb +44 -0
  35. metadata +48 -59
  36. data/lib/cineworld_uk/film.rb +0 -65
  37. data/lib/cineworld_uk/internal/film_with_screenings_parser.rb +0 -69
  38. data/lib/cineworld_uk/internal/screening_parser.rb +0 -132
  39. data/lib/cineworld_uk/internal/website.rb +0 -35
  40. data/lib/cineworld_uk/internal/whatson_parser.rb +0 -36
  41. data/lib/cineworld_uk/screening.rb +0 -87
  42. data/test/fixture_updater.rb +0 -64
  43. data/test/fixtures/cinemas.html +0 -513
  44. data/test/fixtures/information/brighton.html +0 -1268
  45. data/test/fixtures/information/bristol.html +0 -1265
  46. data/test/fixtures/whatson/brighton/film_first.html +0 -207
  47. data/test/fixtures/whatson/brighton/film_last.html +0 -62
  48. data/test/fixtures/whatson/brighton/film_second.html +0 -347
  49. data/test/fixtures/whatson/brighton.html +0 -7508
  50. data/test/fixtures/whatson/glasgow-imax-at-gsc/film_first.html +0 -182
  51. data/test/fixtures/whatson/the-o2-greenwich/film_first.html +0 -167
  52. data/test/lib/cineworld_uk/film_test.rb +0 -142
  53. data/test/lib/cineworld_uk/internal/film_with_screenings_parser_test.rb +0 -101
  54. data/test/lib/cineworld_uk/internal/website_test.rb +0 -57
  55. data/test/lib/cineworld_uk/internal/whatson_parser_test.rb +0 -58
@@ -0,0 +1,81 @@
1
+ module CineworldUk
2
+ # @api private
3
+ module Internal
4
+ module Parser
5
+ module Api
6
+ # Parses a string to derive address
7
+ class CinemaAddress
8
+ # @param [Integer] id the cinema id
9
+ # @return [CineworldUk::Internal::Parser::Api::CinemaAddress]
10
+ def initialize(id)
11
+ @id = id
12
+ end
13
+
14
+ # @return [Hash] contains :street_address, :extended_address,
15
+ # :locality, :postal_code, :country
16
+ # @note Uses the address naming from http://microformats.org/wiki/adr
17
+ def to_hash
18
+ {
19
+ street_address: street_address,
20
+ extended_address: extended_address,
21
+ locality: locality,
22
+ region: region,
23
+ postal_code: postal_code,
24
+ country: 'United Kingdom'.freeze
25
+ }
26
+ end
27
+
28
+ private
29
+
30
+ def adr_array
31
+ @adr_array ||=
32
+ cinema_detail_hash['address'].split(',').map(&:strip).compact
33
+ end
34
+
35
+ def cinema_detail_hash
36
+ @cinema_detail_hash ||= JSON.parse(cinema_detail_response)['cinema']
37
+ end
38
+
39
+ def cinema_detail_response
40
+ @cinema_detail_response ||=
41
+ CineworldUk::Internal::ApiResponse.new.cinema_detail(@id)
42
+ end
43
+
44
+ def ext_array
45
+ @ext_array ||= adr_array[1..-1]
46
+ end
47
+
48
+ def extended_address
49
+ return nil if ext_array.count == 1
50
+ london? ? nil : ext_array[0]
51
+ end
52
+
53
+ def final
54
+ @final ||= ext_array.last
55
+ end
56
+
57
+ def locality
58
+ return ext_array[0] if ext_array.count == 1
59
+ london? ? ext_array[0] : ext_array[1]
60
+ end
61
+
62
+ def london?
63
+ final == 'London'
64
+ end
65
+
66
+ def postal_code
67
+ cinema_detail_hash['postcode']
68
+ end
69
+
70
+ def region
71
+ 'London' if london?
72
+ end
73
+
74
+ def street_address
75
+ adr_array[0]
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,46 @@
1
+ module CineworldUk
2
+ # @api private
3
+ module Internal
4
+ module Parser
5
+ module Api
6
+ # Parses a hash to produce film information
7
+ class Film
8
+ # the cineworld id for the film
9
+ attr_reader :id
10
+
11
+ # @param [Hash] data parsed from performances JSON
12
+ # @return [ CineworldUk::Internal::Parser::Api::Film]
13
+ def initialize(data)
14
+ @data = data
15
+ @id = @data['edi']
16
+ end
17
+
18
+ # Do you need your 3D glasses?
19
+ # @return [String] either '2d' or '3d'
20
+ def dimension
21
+ @data['format'].match(/3D/i) ? '3d' : '2d'
22
+ end
23
+
24
+ # Sanitized film name
25
+ # @return [String]
26
+ def name
27
+ TitleSanitizer.new(@data['originalTitle'] || '').sanitized
28
+ end
29
+
30
+ # List of strings representing different kinds of performance, such
31
+ # as autism, kids, imax, members or q&a
32
+ # @return [Array<String>] or an empty array
33
+ def variant
34
+ [
35
+ @data['title'].match(/Autism Friendly/i) ? 'autism_friendly' : nil,
36
+ @data.fetch('format' || '').match(/IMAX/i) ? 'imax' : nil,
37
+ @data['title'].match(/Movies for Juniors/i) ? 'kids' : nil,
38
+ @data['title'].match(/Unlimited Screening/i) ? 'members' : nil,
39
+ @data['title'].match(/Q (and|&) A/i) ? 'q&a' : nil
40
+ ].compact
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,38 @@
1
+ module CineworldUk
2
+ # @api private
3
+ module Internal
4
+ module Parser
5
+ module Api
6
+ # Parses a string to derive address
7
+ class FilmLookup
8
+ # @return [Hash{Integer => CineworldUk::Internal::Parser::Api::Film}]
9
+ # contains all films & upcoming films keyed by id
10
+ def to_hash
11
+ @to_hash ||= all_films.each_with_object({}) do |item, lookup|
12
+ next if item['edi'].nil?
13
+ lookup[item['edi']] = Film.new(item)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def all_films
20
+ films_data + comingsoon_data
21
+ end
22
+
23
+ def api
24
+ @api ||= CineworldUk::Internal::ApiResponse.new
25
+ end
26
+
27
+ def comingsoon_data
28
+ @comingsoon_data ||= JSON.parse(api.film_list_comingsoon)['films']
29
+ end
30
+
31
+ def films_data
32
+ @films_data ||= JSON.parse(api.film_list)['films']
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,46 @@
1
+ module CineworldUk
2
+ # @api private
3
+ module Internal
4
+ module Parser
5
+ module Api
6
+ # Parses a single json hash to produce time details
7
+ class Performance
8
+ # @param [Hash] data from one performance
9
+ # @return [CineworldUk::Internal::Parser::Api::Performance]
10
+ def initialize(data)
11
+ @data = data
12
+ end
13
+
14
+ # @return [String] direct booking url
15
+ def booking_url
16
+ "http://www.cineworld.co.uk#{@data['url']}"
17
+ end
18
+
19
+ # @return [Integer] id for film lookup
20
+ def film_id
21
+ @data['film']
22
+ end
23
+
24
+ # @return [DateTime] in local time
25
+ def starting_at
26
+ Time.strptime(time_str, '%Y%m%d %H:%S')
27
+ end
28
+
29
+ # @return [Array<String>] includes audio described & subtitled
30
+ def variant
31
+ [
32
+ @data['ad'] ? 'audio_described' : nil,
33
+ @data['subtitled'] ? 'subtitled' : nil
34
+ ].compact
35
+ end
36
+
37
+ private
38
+
39
+ def time_str
40
+ "#{@data['date']} #{@data['time']}"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,50 @@
1
+ module CineworldUk
2
+ # @api private
3
+ module Internal
4
+ module Parser
5
+ module Api
6
+ class PerformancesByDay
7
+ def initialize(cinema_id, date, film_lookup)
8
+ @cinema_id = cinema_id
9
+ @date = date
10
+ @film_lookup = film_lookup
11
+ end
12
+
13
+ def to_a
14
+ performances.map do |performance|
15
+ film = @film_lookup[performance.film_id]
16
+ {
17
+ booking_url: performance.booking_url,
18
+ dimension: film.dimension,
19
+ film_name: film.name,
20
+ starting_at: utc(performance.starting_at),
21
+ variant: (performance.variant + film.variant).sort
22
+ }
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def performances
29
+ parsed_response.map do |hash|
30
+ Internal::Parser::Api::Performance.new(hash)
31
+ end
32
+ end
33
+
34
+ def parsed_response
35
+ JSON.parse(response)['performances']
36
+ end
37
+
38
+ def response
39
+ Internal::ApiResponse.new.performances(@cinema_id, @date)
40
+ end
41
+
42
+ def utc(time)
43
+ time if time.utc?
44
+ TZInfo::Timezone.get('Europe/London').local_to_utc(time)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -3,63 +3,67 @@ module CineworldUk
3
3
  # @api private
4
4
  module Internal
5
5
  # Sanitize and standardize film titles
6
- class TitleSanitizer
7
- # strings and regex to be removed
8
- REMOVE = [
9
- /\s+[23]d/i, # dimension
10
- /\(Hindi\)/i, # Indian Language
11
- /\(Malayalam\)/i, # Indian Language
12
- /\(Punjabi\)/i, # Indian Language
13
- /\(Tamil\)/i, # Indian Language
14
- /\(Turkish\)/i, # Foreign Language
15
- %r(-? \d{1,2}/\d{1,2}/\d{2,4}), # date
16
- /\n/, # newlines
17
- /\- Encore/, # encore
18
- 'Autism Friendly Screening:', # autism screening
19
- '- Unlimited Screening', # unlimited screening
20
- /LFF Opening Night Live/, # london film festival
21
- '- Special Performance', # special performance
22
- /\ATake 2 -/, # take 2
23
- / - (Subtitled) Movies for Juniors/i, # movies for juniors
24
- '(IMAX)', # IMAX
25
- 'SciScreen: ', # SciScreen
26
- ' - Live Q and A', # Live Q&A
27
- /(\s+\-\s+)?MOVIES FOR JUNIORS/i, # movies for juniors
28
- /\bsing\-?a\-?long\b/i, # singalong
29
- ]
6
+ class TitleSanitizer < Cinebase::TitleSanitizer
30
7
 
31
- # regexes and their replacements
32
- REPLACE = {
33
- /Bolshoi Ballet: (.*)/ => 'Bolshoi: ',
34
- /ENO: (.*)/i => 'English National Opera: ',
35
- /Guardian Live - (.*)/ => 'The Guardian: ',
36
- /Met Opera - (.*)/i => 'Met Opera: ',
37
- /NT Live: (.*)/ => 'National Theatre: ',
38
- /NT Live Encore: (.*)/ => 'National Theatre: ',
39
- /ROH - (.*)/ => 'Royal Opera House: ',
40
- /RSC Live: (.*)/ => 'Royal Shakespeare Company: ',
41
- /The Royal Ballet - (.*)/ => 'The Royal Ballet: '
42
- }
8
+ # @!method initialize(title)
9
+ # @param [String] title a film title
10
+ # @return [CineworldUk::Internal::TitleSanitizer]
43
11
 
44
- # @param [String] title a film title
45
- def initialize(title)
46
- @title = title
12
+ # @!method sanitized
13
+ # sanitized and standardized title
14
+ # @return [String] sanitised title
15
+
16
+ private
17
+
18
+ # Strings and regex to be removed
19
+ def remove
20
+ [
21
+ /\s+[23]d/i, # dimension
22
+ /\(Hindi\)/i, # Indian Language
23
+ /\(Malayalam\)/i, # Indian Language
24
+ /\(Punjabi\)/i, # Indian Language
25
+ /\(Tamil\)/i, # Indian Language
26
+ /\(Cantonese\)/i, # Chinese
27
+ /\(Turkish\)/i, # Foreign Language
28
+ %r(-? \d{1,2}/\d{1,2}/\d{2,4}), # date
29
+ /\n/, # newlines
30
+ /\- Encore/, # encore
31
+ /Autism Friendly Screening\s*[:-] /, # autism screening
32
+ '- Unlimited Screening', # unlimited screening
33
+ /LFF Opening Night Live/, # london film festival
34
+ '- Special Performance', # special performance
35
+ /\ATake 2 -/, # take 2
36
+ / - (Subtitled) Movies for Juniors/i, # movies for juniors
37
+ '(IMAX)', # IMAX
38
+ 'SciScreen: ', # SciScreen
39
+ /\s(-\s)*(With)*\sLive Q And A/i, # Live Q&A
40
+ /(\s+\-\s+)?MOVIES FOR JUNIORS/i, # movies for juniors
41
+ /\bsing\-?a\-?long\b/i, # singalong
42
+ %r{\s20\d{2}[\/-]20\d{2} Season\b}
43
+ ]
47
44
  end
48
45
 
49
- # sanitized and standardized title
50
- # @return [String] title
51
- def sanitized
52
- @sanitzed ||= begin
53
- sanitized = @title
54
- REMOVE.each do |pattern|
55
- sanitized.gsub! pattern, ''
56
- end
57
- REPLACE.each do |pattern, prefix|
58
- sanitized.gsub!(pattern) { |_| prefix + $1 }
59
- end
60
- sanitized.squeeze(' ').strip
61
- end
46
+ # Regexes and their replacements
47
+ def replace
48
+ {
49
+ /Bolshoi Ballet\s*[:-] (.*)/ => 'Bolshoi Ballet: ',
50
+ /ENO\s*[:-] (.*)/i => 'English National Opera: ',
51
+ /Guardian Live\s*[:-] (.*)/ => 'The Guardian: ',
52
+ /Glyndebourne 20\d{2}\s*[:-] (.*)/ => 'Glyndebourne: ',
53
+ /Met Opera\s*[:-] (.*)/i => 'Met Opera: ',
54
+ /NT Live\s*[:-] (.*)/ => 'National Theatre: ',
55
+ /NT Live Encore\s*[:-] (.*)/ => 'National Theatre: ',
56
+ /ROH\s*[:-] (.*)/ => 'Royal Opera House: ',
57
+ /ROH Royal Opera\s*[:-] (.*)/ => 'Royal Opera House: ',
58
+ /RSC Live\s*[:-] (.*)/ => 'Royal Shakespeare Company: ',
59
+ /The Royal Ballet\s*[:-] (.*)/ => 'The Royal Ballet: ',
60
+ /Royal Ballet\s*[:-] (.*)/ => 'The Royal Ballet: ',
61
+ /ROH The Royal Ballet\s*[:-] (.*)/ => 'The Royal Ballet: ',
62
+ /Royal Ballet Live\s*[:-] (.*)/ => 'The Royal Ballet: ',
63
+ /San Francisco Ballets (.*)/ => 'San Francisco Ballet: '
64
+ }
62
65
  end
66
+
63
67
  end
64
68
  end
65
69
  end
@@ -0,0 +1,78 @@
1
+ module CineworldUk
2
+ # The object representing a single screening on the Cineworld UK website
3
+ class Performance < Cinebase::Performance
4
+ # @!attribute [r] booking_url
5
+ # @return [String] the booking URL on the cinema website
6
+ # @!attribute [r] cinema_name
7
+ # @return [String] the cinema name
8
+ # @!attribute [r] cinema_id
9
+ # @return [String] the cinema id
10
+ # @!attribute [r] dimension
11
+ # @return [String] 2d or 3d
12
+ # @!attribute [r] film_name
13
+ # @return [String] the film name
14
+
15
+ # @!method initialize(options)
16
+ # @param [Hash] options options hash
17
+ # @option options [String] :booking_url (nil) buying url for the screening
18
+ # @option options [String] :cinema_name name of the cinema
19
+ # @option options [String] :cinema_id website id of the cinema
20
+ # @option options [String] :dimension ('2d') dimension of the screening
21
+ # @option options [String] :film_name name of the film
22
+ # @option options [Time] :starting_at listed start time of the performance
23
+
24
+ # All currently listed films showing at a cinema
25
+ # @param [Integer] cinema_id id of the cinema on the website
26
+ # @return [Array<CineworldUk::Screening>]
27
+ def self.at(cinema_id)
28
+ dates(cinema_id).flat_map do |date|
29
+ performances_on(cinema_id, date).flat_map do |p|
30
+ new cinema_hash(cinema_id).merge(p)
31
+ end
32
+ end
33
+ end
34
+
35
+ # @!method showing_on
36
+ # The date of the screening
37
+ # @return [Date]
38
+
39
+ # @!method starting_at
40
+ # UTC time of the screening
41
+ # @return [Time]
42
+
43
+ # @!method variant
44
+ # The kinds of screening (IMAX, kids, baby, senior)
45
+ # @return <Array[String]>
46
+
47
+ private
48
+
49
+ # @api private
50
+ def self.api
51
+ @api ||= Internal::ApiResponse.new
52
+ end
53
+
54
+ # @api private
55
+ def self.cinema_hash(cinema_id)
56
+ {
57
+ cinema_id: cinema_id,
58
+ cinema_name: CineworldUk::Cinema.new(cinema_id).name
59
+ }
60
+ end
61
+
62
+ # @api private
63
+ def self.dates(cinema_id)
64
+ @dates ||= JSON.parse(api.dates(cinema_id))['dates'].map do |str|
65
+ Date.strptime(str, '%Y%m%d')
66
+ end
67
+ end
68
+
69
+ # @api private
70
+ def self.films
71
+ @films ||= Internal::Parser::Api::FilmLookup.new.to_hash
72
+ end
73
+
74
+ def self.performances_on(cinema_id, date)
75
+ Internal::Parser::Api::PerformancesByDay.new(cinema_id, date, films).to_a
76
+ end
77
+ end
78
+ end
@@ -1,6 +1,6 @@
1
1
  # Ruby interface for http://www.cineworld.co.uk
2
- # @version 2.1.6
2
+ # @version 3.0.0
3
3
  module CineworldUk
4
4
  # Gem version
5
- VERSION = '2.1.6'
5
+ VERSION = '3.0.0'
6
6
  end
data/lib/cineworld_uk.rb CHANGED
@@ -1,18 +1,21 @@
1
+ require 'json'
2
+
3
+ require 'cinebase'
1
4
  require 'nokogiri'
2
- require 'tzinfo'
3
- require 'tzinfo/data'
4
5
 
5
6
  require_relative './cineworld_uk/version'
6
7
 
7
- require_relative './cineworld_uk/internal/film_with_screenings_parser'
8
- require_relative './cineworld_uk/internal/screening_parser'
8
+ require_relative './cineworld_uk/internal/api_response'
9
+ require_relative './cineworld_uk/internal/parser/api/cinema_address'
10
+ require_relative './cineworld_uk/internal/parser/api/film'
11
+ require_relative './cineworld_uk/internal/parser/api/film_lookup'
12
+ require_relative './cineworld_uk/internal/parser/api/performances_by_day'
13
+ require_relative './cineworld_uk/internal/parser/api/performance'
14
+
9
15
  require_relative './cineworld_uk/internal/title_sanitizer'
10
- require_relative './cineworld_uk/internal/whatson_parser'
11
- require_relative './cineworld_uk/internal/website'
12
16
 
13
17
  require_relative './cineworld_uk/cinema'
14
- require_relative './cineworld_uk/film'
15
- require_relative './cineworld_uk/screening'
18
+ require_relative './cineworld_uk/performance'
16
19
 
17
20
  # cineworld_uk gem
18
21
  module CineworldUk
@@ -0,0 +1 @@
1
+ {"cinema":{"id":10,"name":"London - Chelsea","address":"279 Kings Road,Chelsea, London","postcode":"SW3 5EW","tel":"0871 200 2000","services":["con","ns","vh","3d","sb","hfr","etx","ad","dig","gdog","adv"]}}
@@ -0,0 +1 @@
1
+ {"cinema":{"id":21,"name":"Edinburgh","address":"Fountain Park,130/3 Dundee Street, Edinburgh","postcode":"EH11 1AF","tel":"0871 200 2000","services":["con","ns","cb","vh","stb","ix","dba","au","3d","dbp","sb","hfr","etx","ad","dig","m4j","bas","bar","gdog","adv"]}}
@@ -0,0 +1 @@
1
+ {"cinema":{"id":3,"name":"Brighton","address":"Brighton Marina Village, Brighton","postcode":"BN2 5UF","tel":"0871 200 2000","services":["ns","cb","vh","dba","au","3d","dbp","sb","hfr","ad","etx","dig","m4j","bas","gdog","adv"]}}
@@ -0,0 +1 @@
1
+ {"cinema":{"id":96,"name":"Birmingham - NEC","address":"Resorts World, Pendigo Way, Birmingham","postcode":"B40 1PU","tel":"0871 200 2000","services":["con","ns","park","vh","stb","ix","dba","au","3d","dbp","sb","hfr","etx","ad","dig","m4j","bas","gdog","adv"]}}
@@ -0,0 +1 @@
1
+ {"cinemas":[{"id":1,"name":"Aberdeen - Queens Links","address":"Queens Links Leisure Park, Links Road, Aberdeen","latitude":57.150261,"longitude":-2.077969},{"id":78,"name":"Aberdeen - Union Square","address":"26 First Level Mall, Union Square, Guild Square, Aberdeen","latitude":57.14292,"longitude":-2.09637},{"id":87,"name":"Aldershot","address":"Westgate, Aldershot","latitude":51.250679,"longitude":-0.768437},{"id":12,"name":"Ashford","address":"Eureka Entertainment Centre, Rutherford Road, Ashford","latitude":51.160915,"longitude":0.872751},{"id":23,"name":"Ashton-under-Lyne","address":"Ashton Leisure Park, Fold Way,","latitude":53.489052,"longitude":-2.111577},{"id":34,"name":"Bedford","address":"Aspects Leisure Centre, Newnham Avenue, Bedford","latitude":52.133323,"longitude":-0.445841},{"id":56,"name":"Birmingham - Broad Street","address":"181 Broad Street, Birmingham","latitude":52.473815,"longitude":-1.915563},{"id":96,"name":"Birmingham - NEC","address":"Resorts World, Pendigo Way, Birmingham","latitude":52.4481,"longitude":-1.71768},{"id":67,"name":"Boldon Tyne and Wear","address":"Boldon Leisure Park, Bolden Colliery, Tyne and Wear","latitude":54.946793,"longitude":-1.46633},{"id":72,"name":"Bolton","address":"The Valley, 15 Eagley Brook Way, Bolton","latitude":53.5972,"longitude":-2.423955},{"id":73,"name":"Bradford","address":"Bradford Leisure Exchange, Vicar Lane, Bradford","latitude":53.791623,"longitude":-1.747758},{"id":2,"name":"Braintree","address":"Freeport Leisure, Charter Way, Braintree","latitude":51.869987,"longitude":0.570995},{"id":3,"name":"Brighton","address":"Brighton Marina Village, Brighton","latitude":50.812631,"longitude":-0.100665},{"id":4,"name":"Bristol","address":"Hengrove Leisure Park, Hengrove Way, Bristol","latitude":51.416345,"longitude":-2.587141},{"id":94,"name":"Broughton","address":"Broughton Shopping Park, Chester Road, Broughton","latitude":53.168578,"longitude":-2.9736962},{"id":5,"name":"Burton upon Trent","address":"Middle Way Park, Guild Street, Burton upon Trent","latitude":52.805612,"longitude":-1.632458},{"id":6,"name":"Bury St Edmunds","address":"Parkway, Bury St Edmunds","latitude":52.246215,"longitude":0.706635},{"id":8,"name":"Cardiff","address":"Mary Ann Street, Cardiff","latitude":51.478737,"longitude":-3.173405},{"id":9,"name":"Castleford","address":"Xscape, Colorado Way, Castleford","latitude":53.710189,"longitude":-1.3419},{"id":11,"name":"Cheltenham","address":"The Brewery, Oxford Passage, St Margaret's Road, Cheltenham","latitude":51.902932,"longitude":-2.075018},{"id":14,"name":"Chesterfield","address":"Alma Leisure Park, Derby Road, Chesterfield","latitude":53.227163,"longitude":-1.424189},{"id":15,"name":"Chichester","address":"Chichester Gate, Chichester","latitude":50.830007,"longitude":-0.785063},{"id":16,"name":"Crawley","address":"Crawley Leisure Park, London Road, Crawley","latitude":51.120824,"longitude":-0.189681},{"id":17,"name":"Didcot","address":"27 Station Road, Didcot","latitude":51.608236,"longitude":-1.239831},{"id":18,"name":"Didsbury","address":"Parrs Wood Entertainment Centre, Wilmslow Road, Manchester","latitude":53.407806,"longitude":-2.220271},{"id":19,"name":"Dundee","address":"Camperdown Leisure Park, Kingsway West, Dundee","latitude":56.484384,"longitude":-3.046191},{"id":20,"name":"Eastbourne","address":"Sovereign Harbour Retail Park, Pevensey Bay Road, Eastbourne","latitude":50.794848,"longitude":0.322874},{"id":21,"name":"Edinburgh","address":"Fountain Park,130/3 Dundee Street, Edinburgh","latitude":55.941936,"longitude":-3.216934},{"id":24,"name":"Falkirk","address":"Central Retail Park, Old Bison Works, Falkirk","latitude":56.003768,"longitude":-3.779896},{"id":88,"name":"Glasgow - IMAX at GSC","address":"Glasgow Science Centre, 50 Pacific Quay, Glasgow","latitude":55.860201,"longitude":-4.293809},{"id":27,"name":"Glasgow - Parkhead","address":"Forge Shopping Centre, 1221 Gallowgate, Glasgow","latitude":55.853437,"longitude":-4.199809},{"id":28,"name":"Glasgow - Renfrew Street","address":"7 Renfrew Street, Glasgow","latitude":55.8649,"longitude":-4.255164},{"id":95,"name":"Glasgow - Silverburn","address":"Silverburn Shopping Centre, 763 Barrhead Road, Glasgow","latitude":55.821616,"longitude":-4.34184},{"id":90,"name":"Gloucester Quays","address":"Gloucester Quays Outlet Centre, Merchants Road, Gloucester","latitude":51.86083,"longitude":-2.25256},{"id":31,"name":"Harlow","address":"Queensgate Centre, Edinburgh Way, Harlow","latitude":51.783882,"longitude":0.108092},{"id":76,"name":"Haverhill","address":"Ehringshausen Way, Haverhill","latitude":52.08379,"longitude":0.43978},{"id":33,"name":"High Wycombe","address":"Denmark Street, Eden, High Wycombe","latitude":51.629055,"longitude":-0.753768},{"id":99,"name":"Hinckley","address":"The Crescent, Station Road, Hinckley","latitude":52.539345,"longitude":-1.372837},{"id":35,"name":"Hull","address":"Kingswood Retail Park, Gibraltar Road, Hull","latitude":53.79138,"longitude":-0.353455},{"id":36,"name":"Huntingdon","address":"Tower Field Leisure Park, Abbots Ripton Road, Huntingdon","latitude":52.351424,"longitude":-0.18068},{"id":38,"name":"Ipswich","address":"Cardinal Park, 11 Grafton Way, Ipswich","latitude":52.053234,"longitude":1.151031},{"id":39,"name":"Isle Of Wight","address":"Coppins Bridge, Newport, Isle of Wight","latitude":50.69895,"longitude":-1.289221},{"id":40,"name":"Jersey","address":"The Waterfront Centre, La Rue de L'Etau, St Helier","latitude":49.18315,"longitude":-2.11444},{"id":83,"name":"Leigh","address":"The Loom, Spinning Jenny Way, Leigh","latitude":53.494058,"longitude":-2.515247},{"id":41,"name":"Liverpool","address":"Montrose Way, Edge Lane Retail Park, Liverpool","latitude":53.408669,"longitude":-2.924922},{"id":42,"name":"Llandudno","address":"Junction Leisure Park, Llandudno Junction","latitude":53.282287,"longitude":-3.80842},{"id":45,"name":"London - Bexleyheath","address":"28-70 Broadway, Bexleyheath","latitude":51.456276,"longitude":0.150067},{"id":10,"name":"London - Chelsea","address":"279 Kings Road,Chelsea, London","latitude":51.485333,"longitude":-0.173527},{"id":22,"name":"London - Enfield","address":"Southbury Leisure Centre, 208 Southbury Road, Enfield","latitude":51.65255,"longitude":-0.061396},{"id":25,"name":"London - Feltham","address":"Leisure West, Air Park Way, Feltham","latitude":51.443895,"longitude":-0.404602},{"id":26,"name":"London - Fulham Road","address":"142 Fulham Road, London","latitude":51.487151,"longitude":-0.179403},{"id":30,"name":"London - Hammersmith","address":"207 King Street, Hammersmith, London","latitude":51.492525,"longitude":-0.233282},{"id":32,"name":"London - Haymarket","address":"63-65 Haymarket, London","latitude":51.508803,"longitude":-0.132368},{"id":37,"name":"London - Ilford","address":"I-Scene, Clements Road, Ilford","latitude":51.557635,"longitude":0.074141},{"id":60,"name":"London - Staples Corner","address":"Staples Corner Retail Park, Geron Way, London","latitude":51.570292,"longitude":-0.229691},{"id":79,"name":"London - The O2, Greenwich ","address":"The O2, Peninsula Square, London","latitude":51.50265,"longitude":0.00309},{"id":65,"name":"London - Wandsworth","address":"Southside Shopping Centre, Wandsworth High Street, London","latitude":51.455401,"longitude":-0.194168},{"id":89,"name":"London - Wembley","address":"London Designer Outlet, Wembley Park Boulevard, London","latitude":51.556763,"longitude":-0.282136},{"id":66,"name":"London - West India Quay","address":"Hertsmere Road, West India Quay, London","latitude":51.507645,"longitude":-0.023818},{"id":70,"name":"London - Wood Green","address":"The Mall Wood Green, High Road, London","latitude":51.594545,"longitude":-0.106431},{"id":43,"name":"Luton","address":"The Galaxy, Bridge Street, Luton","latitude":51.881856,"longitude":-0.417634},{"id":44,"name":"Middlesbrough","address":"Middlesbrough Leisure Park, Marton Road, Middlesbrough","latitude":54.574667,"longitude":-1.226274},{"id":46,"name":"Milton Keynes","address":"Xscape, 602 Marlborough Gate, Milton Keynes","latitude":52.041437,"longitude":-0.748677},{"id":97,"name":"Newport - Friars Walk","address":"Friars Walk Shopping Centre, Usk Plaza, Newport ","latitude":51.585901,"longitude":-2.9925405},{"id":47,"name":"Newport - Spytty Park","address":"Newport Retail Park, Spytty Road, Newport","latitude":51.577571,"longitude":-2.943588},{"id":48,"name":"Northampton","address":"Sixfields Leisure, Weedon Road, Northampton","latitude":52.236796,"longitude":-0.936617},{"id":49,"name":"Nottingham","address":"The Corner House, 29 Forman Street, Nottingham","latitude":52.955422,"longitude":-1.1498},{"id":50,"name":"Rochester","address":"Medway Valley Leisure Park, Chariot Way, Rochester","latitude":51.380031,"longitude":0.477112},{"id":51,"name":"Rugby","address":"Junction One, Leicester Road, Rugby","latitude":52.38524,"longitude":-1.259169},{"id":52,"name":"Runcorn","address":"Trident Park, Halton Lea, Runcorn","latitude":53.326199,"longitude":-2.699966},{"id":54,"name":"Sheffield","address":"Valley Centertainment, Broughton Lane, Sheffield","latitude":53.401537,"longitude":-1.414966},{"id":55,"name":"Shrewsbury","address":"Old Potts Way, Shrewsbury","latitude":52.703548,"longitude":-2.74053},{"id":57,"name":"Solihull","address":"47 Mill Lane Arcade (Upper), Touchwood, Solihull,","latitude":52.412453,"longitude":-1.778998},{"id":58,"name":"Southampton","address":"Ocean Village, 4 Ocean Way, Southampton","latitude":50.895184,"longitude":-1.394929},{"id":59,"name":"St Helens","address":"Chalon Way West, St Helens","latitude":53.451379,"longitude":-2.739894},{"id":91,"name":"St Neots","address":"The Rowley Arts Centre, Huntingdon Street, St Neots","latitude":52.229032,"longitude":-0.265743},{"id":61,"name":"Stevenage","address":"Unit 4, Stevenage Leisure Park, Kings Way, Stevenage","latitude":51.899912,"longitude":-0.20823},{"id":62,"name":"Stockport","address":"Railway Road, Stockport","latitude":53.406912,"longitude":-2.160925},{"id":107,"name":"Stoke-on-Trent","address":"Quadrant Road, City Centre, Stoke-on-Trent","latitude":53.0275517,"longitude":-2.1759024},{"id":93,"name":"Swindon - Regent Circus","address":"Victoria Road, Swindon","latitude":51.5581409,"longitude":-1.7803051},{"id":63,"name":"Swindon - Shaw Ridge","address":"Shaw Ridge Leisure Park, Whitehill Way, Swindon","latitude":51.560798,"longitude":-1.831324},{"id":92,"name":"Telford","address":"Southwater Square, Telford","latitude":52.673955,"longitude":-2.446977},{"id":64,"name":"Wakefield","address":"Westgate Retail and Leisure Park, Colinsway, Wakefield","latitude":53.677164,"longitude":-1.506107},{"id":68,"name":"Weymouth","address":"New Bond St, Weymouth","latitude":50.610226,"longitude":-2.455118},{"id":98,"name":"Whiteley","address":"Whiteley Shopping Centre, Whiteley Way, Fareham","latitude":50.886055,"longitude":-1.248155},{"id":77,"name":"Witney","address":"Marriotts Walk, Witney","latitude":51.786886,"longitude":-1.48685},{"id":69,"name":"Wolverhampton","address":"Bentley Bridge Leisure Park, Wednesfield Way, Wolverhampton","latitude":52.596287,"longitude":-2.093196},{"id":71,"name":"Yeovil","address":"Yeo Leisure Park, Old Station Way, Yeovil","latitude":50.940361,"longitude":-2.62553}]}
@@ -0,0 +1 @@
1
+ {"dates":["20160204","20160205","20160206","20160207","20160208","20160209","20160210","20160211","20160214","20160225","20160303","20160328"]}