cineworld_uk 2.1.6 → 3.0.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.
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"]}