diff --git a/README.md b/README.md
index eed73de..9d22bd5 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
-#
{Malls parser skill neon}
+#
{Mall guide skill neon}
## Summary
-Skill for mall parsing
+Skill for guiding around the mall.
## Description
-Skill parses mall web page and returns user name, location and work hours of requested shop, store
+Skill parses mall web page and returns user: name, location and work hours of requested shop, store
## Examples
- where is apple?
diff --git a/__init__.py b/__init__.py
index e6acc2f..1c96346 100644
--- a/__init__.py
+++ b/__init__.py
@@ -27,13 +27,17 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+from fileinput import close
from neon_utils.skills.neon_skill import NeonSkill, LOG
from mycroft.skills.core import intent_file_handler
-from .request_handling import RequestHandler
from .request_handling import existing_lang_check, get_shop_data,\
shop_selection_by_floors,\
- location_format,\
- curent_time_extraction
+ location_format
+
+
+from .time_calculations_handling import current_time_extraction,\
+ time_calculation
+
import re
@@ -43,6 +47,7 @@ class DirectorySkill(NeonSkill):
def __init__(self):
super(DirectorySkill, self).__init__(name="DirectorySkill")
self.url = "https://www.alamoanacenter.com/en/directory/"
+ self.user_floor = 'one'
def initialize(self):
@@ -111,170 +116,59 @@ def start_again(self):
LOG.info(f'another shop {another_shop}')
return another_shop
elif start_again == "no":
- self.speak_dialog('no_shop_request')
+ return None
else:
self.speak_dialog('unexpected_error')
return None
- def speak_shops(self, shop_info):
+ def speak_shops(self, shop):
"""
Speaks shop info that was found.
Substitutes time format for better pronunciation.
- speak_dialog('found_shop', {"name": shop['name'], "hours": hours, "location": location})
+ speak_dialog('found_shop', {"name": shop['name'], "hours": hours, "location": location, "open": shop['open']})
Shows shop label image in gui.
Args:
shop_info (list): found shops on user's
request
"""
- for shop in shop_info:
- LOG.info(shop)
- location = location_format(shop['location'])
- hours = re.sub('(\d+)am.+(\d+)pm', r'from \1 A M to \2 P M', shop['hours'])
- self.speak_dialog('found_shop', {"name": shop['name'], "hours": hours, "location": location})
- LOG.info({"name": shop['name'], "hours": hours, "location": location})
- self.gui.show_image(shop['logo'], caption=f'{hours} {location}', title=shop['name'])
-
- def location_selection(self, shop_info):
- """
- If there are several shops in found shops list
- and user wants to get shop info on the certain
- floor. If shop on that floor exists speaks
- this shop info. Else speaks all shops info.
- Args:
- shop_info (list): found shops on user's
- request
- Returns:
- 3, None (to ask for another shop info)
- """
- LOG.info(f"Shop by location selection {shop_info}")
- floor = self.get_response('which_floor')
- shops = shop_selection_by_floors(floor, shop_info)
- if shops:
- self.speak_shops(shops)
+ LOG.info(f"speak shops {shop}")
+ location = location_format(shop['location'])
+ hours = re.sub('(\d+)am.+(\d+)pm', r'from \1 A M to \2 P M', shop['hours'])
+ if 'level' in location.lower():
+ self.speak_dialog('found_shop', {"name": shop['name'], "hours": hours, "location": location, "on": 'on', "open": shop['open']})
else:
- self.speak_dialog('no_shop_on_level')
- self.speak_shops(shop_info)
- return 3, None
+ self.speak_dialog('found_shop', {"name": shop['name'], "hours": hours, "location": location, "on": '', "open": shop['open']})
+ self.gui.show_image(shop['logo'], caption=f'{hours} {location}', title=shop['name'])
- def open_shops_search(self, shop_info, day_time, hour, min):
- """
- Selects open shops. Collects the list of
- open shops else return empty list.
- Args:
- shop_info (list): found shops on user's
- request
- Returns:
- shop_info (list): open shops
- """
- open_shops = []
- LOG.info(f"User's time {day_time, hour, min}")
- for shop in shop_info:
- parse_time = re.findall(r'(\d+)+[am|pm]', shop['hours'])
- LOG.info(f'Parsed time {parse_time}')
- open_time = int(parse_time[0])
- close_time = int(parse_time[1])
- if open_time <= hour < close_time:
- open_shops.append(shop)
- elif day_time[1] == 'am' and open_time <= hour:
- open_shops.append(shop)
- return open_shops
+ def speak_in_time_order(self, shop):
+ self.speak_shops(shop[2])
+ if shop[2]['open'] == 'open' and shop[0]:
+ self.speak_dialog('closing_minutes', {'closing_minutes': shop[0]})
+ elif shop[2]['open'] == 'closed' and shop[0] and shop[1]:
+ self.speak_dialog('opening_hours', {'wait_h': shop[1], 'wait_min': shop[0]})
+ elif shop[2]['open'] == 'closed' and shop[0]:
+ self.speak_dialog('opening_minutes', {'wait_min': shop[0]})
- def time_calculation(self, shop_info, open, day_time, hour, min):
- # add logic if shop opens and closes not at am-pm time period
- # change to speak dialog
- """
- Calculates time difference between user's current time
- and shop working hours.
- If 'open' argument is True:
- If user one hour or less before closing: speaks how
- many minutes left. Speaks shop info.
- Else speaks corresponging dialog.
- Speaks shop info.
- If 'open' argument is False:
- Speaks corresponding dialog.
- If user is one hour or less before opening hours
- speaks how much time is left for waiting.
- If user's time is 'am' and user is before opening
- hours, speaks how many hours and minutes left
- waiting.
- If user's time is evening (pm) speaks when the shop
- opens in the morning.
- Speaks shop info.
- Args:
- shop_info (list): found shops on user's request
- open (boolean): True - if shop is open
- day_time (str): user's current day time (am|pm)
- hour (int): user's current hour
- min (int): user's current minute
- Returns:
- 3, None (to ask for another shop info)
- Examples:
- work time 9am-10pm
- user's time 8am
- Prompt: 'Shop is closed now. Opens in 1 hour'
- """
+ def first_from_many(self, shop_info, shops_on_the_floor):
+ first_shop = {}
for shop in shop_info:
- work_time = shop['hours']
- normalized_time = re.findall(r'(\d+)[am|pm]', work_time)
- open_time = int(normalized_time[0])
- close_time = int(normalized_time[1])
- LOG.info(f'work_time {work_time}')
- shop_name = shop['name']
- parse_time = work_time.split('-')
- LOG.info(f'parse_time {parse_time}')
- # time left
- wait_h = open_time - hour - 1
- wait_min = 60 - min
- if open:
- if day_time[1] == 'pm' and 0 < (close_time - hour) <= 1:
- LOG.info(f'{shop_name} closes in {wait_min} minutes.')
- self.speak_dialog('closing_minutes', {"shop_name": shop_name, "wait_min": wait_min})
- else:
- LOG.info(f'{shop_name} is open.')
- self.speak_dialog('open_now', {'shop_name': shop_name})
- LOG.info([shop])
- self.speak_shops([shop])
- else:
- if day_time[1] == 'am' and hour < open_time:
- if wait_h == 0:
- LOG.info(f'{shop_name} is closed now. Opens in {wait_min} minutes')
- self.speak_dialog('opening_minutes', {"shop_name": shop_name, "wait_min": wait_min})
- else:
- LOG.info(f'{shop_name} is closed now. Opens in {wait_h} hour and {wait_min} minutes')
- self.speak_dialog('opening_hours', {"shop_name": shop_name, "wait_h": wait_h, "wait_min": wait_min})
- elif hour >= close_time:
- LOG.info(f'{shop_name} is closed now. Shop opens at {open_time}')
- self.speak_dialog('closed_now', {'shop_name': shop_name, 'open_time': open_time})
- LOG.info([shop])
- self.speak_shops([shop])
- return 3, None
-
- def shops_by_time_selection(self, shop_info):
- """
- If user chose to select shops by time or
- use like default selection. Gets user's
- current time. Selects open shops.
- Args:
- shop_info (list): found shops on user's
- request
- Returns:
- time_calculation function with True
- in 'open' argument.
- time_calculation function with False
- in 'open' argument. (if list
- of open shops is 0)
-
- """
- LOG.info(f"Shop by time selection {shop_info}")
- day_time, hour, min = curent_time_extraction()
- # day_time, hour, min = ['11:15', 'pm'], 11, 15
- open_shops = self.open_shops_search(shop_info, day_time, hour, min)
- if len(open_shops) >= 1:
- return self.time_calculation(open_shops, True, day_time, hour, min)
- else:
- return self.time_calculation(shop_info, False, day_time, hour, min)
-
+ if shop[2]['open'] == 'open':
+ if shop in shops_on_the_floor:
+ first_shop = shop
+ return first_shop
+ for shop in shop_info:
+ if shop[2]['open'] == 'open':
+ first_shop = shop
+ return first_shop
+ for shop in shop_info:
+ if shop in shops_on_the_floor:
+ first_shop = shop
+ return first_shop
+ first_shop = shops_on_the_floor[0]
+ return first_shop
+ return first_shop
+
def find_shop(self, user_request, mall_link):
"""
When the intent is matched, user_request
@@ -309,45 +203,80 @@ def find_shop(self, user_request, mall_link):
LOG.info(f'user_request {user_request}')
LOG.info(f'mall_link {mall_link}')
if user_request is not None:
- self.speak_dialog("start_parsing")
- LOG.info(f"I am parsing shops and malls for your request")
- file_path = self.file_system.path
- LOG.info(f'file_path {file_path}')
- shop_info = get_shop_data(mall_link, user_request, file_path)
- LOG.info(f"I found {len(shop_info)} shops")
- LOG.info(f"shop list: {shop_info}")
+ dir_path = self.root_dir
+ shop_info = get_shop_data(mall_link, user_request, dir_path)
+ day_time, hour, min = current_time_extraction()
if len(shop_info) == 0:
user_request = self.get_response('shop_not_found')
return 1, user_request
- elif len(shop_info) > 1:
- self.speak_dialog('more_than_one')
- # ask for the way of selection: time, location, nothing
- sorting_selection = self.get_response('choose_selection')
- if sorting_selection:
- LOG.info(f'Users answer on sorting options: {sorting_selection}')
- if self.voc_match(sorting_selection, "time"):
- LOG.info('Time sorting selected')
- return self.shops_by_time_selection(shop_info)
- elif self.voc_match(sorting_selection, "location"):
- LOG.info('Location sorting selected')
- return self.location_selection(shop_info)
- elif self.voc_match(sorting_selection, "no"):
- LOG.info('No sorting selected. Sorting by time on default.')
- return self.shops_by_time_selection(shop_info)
- else:
- LOG.info('Nothing matched. Sorting by time on default.')
- return self.shops_by_time_selection(shop_info)
+ elif len(shop_info) > 2:
+ LOG.info(f"more_than_two: n = {len(shop_info)}, store {shop_info[0]['name']}")
+ self.speak_dialog('shops_amount', {'n': len(shop_info), 'loc_amount': 'locations', 'store_name': shop_info[0]["name"]})
+ # contains list of open and closed shops
+ shop_info = time_calculation(shop_info, day_time, hour, min)
+ # collect list of shops on user's floor
+ shops_on_the_floor = shop_selection_by_floors(self.user_floor, shop_info)
+ LOG.info(f'shops_on_the_floor {shops_on_the_floor}')
+ # speak first shop
+ first_shop = self.first_from_many(shop_info, shops_on_the_floor)
+ self.speak_in_time_order(first_shop)
+ # ask for other shops info showing
+ more_info = self.ask_yesno('more_shops_info', {'shop_name': shop_info[0][2]["name"]})
+ if more_info == 'yes':
+ # ask for the way of selection: time, location, nothing
+ sorting_selection = self.get_response('choose_selection')
+ if sorting_selection:
+ LOG.info(f'Users answer on sorting options: {sorting_selection}')
+ if self.voc_match(sorting_selection, "time"):
+ for shop in shop_info:
+ self.speak_in_time_order(shop)
+ return 3, None
+ elif self.voc_match(sorting_selection, "location"):
+ LOG.info('Location sorting selected')
+ if shops_on_the_floor:
+ self.speak_dialog('shops_on_user_floor', {'n': len(shops_on_the_floor),
+ 'store_name': shop_info[0][2]["name"]})
+ for shop in shops_on_the_floor:
+ self.speak_in_time_order(shop)
+ if len(shops_on_the_floor) != len(shop_info):
+ self.speak_dialog('another_shop_locations')
+ for shop in shop_info:
+ if shop not in shops_on_the_floor:
+ self.speak_in_time_order(shop)
+ return 3, None
+ else:
+ self.speak_dialog('no_shop_on_level')
+ self.speak_dialog('all_locations', {'store_name':shop_info[0][2]['name']})
+ for shop in shop_info:
+ self.speak_in_time_order(shop)
+ return 3, None
+ else:
+ LOG.info('No sorting selected. Sorting by time on default.')
+ self.speak_dialog('by_time_sorting')
+ for shop in shop_info:
+ self.speak_in_time_order(shop)
+ return 3, None
else:
- LOG.info(f"found shop {shop_info}")
- self.speak_shops(shop_info)
+ LOG.info(f"found shop/s {shop_info}")
+ shop_info = time_calculation(shop_info, day_time, hour, min)
+ if len(shop_info) == 1:
+ self.speak_dialog('shops_amount', {'n': len(shop_info), 'loc_amount': 'location', 'store_name': shop_info[0][2]["name"]})
+ else:
+ self.speak_dialog('shops_amount', {'n': len(shop_info), 'loc_amount': 'locations', 'store_name': shop_info[0][2]["name"]})
+ LOG.info(f'shop info after time calculation {shop_info}')
+ for shop in shop_info:
+ self.speak_in_time_order(shop)
return 3, None
def execute(self, user_request, mall_link):
count = 0
LOG.info('Start execute')
- while count < 3 and user_request is not None and mall_link is not None:
+ while count < 2 and user_request is not None and mall_link is not None:
+ LOG.info(str(count))
new_count, user_request = self.find_shop(user_request, mall_link)
count = count + new_count
+ if count == 2 and user_request is not None and mall_link is not None:
+ new_count, user_request = self.find_shop(user_request, mall_link)
user_request = self.start_again()
LOG.info(str(user_request))
if user_request is not None:
diff --git a/locale/en-us/dialog/en/all_locations.dialog b/locale/en-us/dialog/en/all_locations.dialog
index fbffb2a..bd65901 100644
--- a/locale/en-us/dialog/en/all_locations.dialog
+++ b/locale/en-us/dialog/en/all_locations.dialog
@@ -1 +1 @@
-Here are all possible shop locations.
\ No newline at end of file
+All {{store_name}} locations are:
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/another_shop.dialog b/locale/en-us/dialog/en/another_shop.dialog
index be4fbfd..932bcda 100644
--- a/locale/en-us/dialog/en/another_shop.dialog
+++ b/locale/en-us/dialog/en/another_shop.dialog
@@ -1 +1 @@
-What shop you are looking for?
\ No newline at end of file
+What store are you looking for?
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/another_shop_locations.dialog b/locale/en-us/dialog/en/another_shop_locations.dialog
new file mode 100644
index 0000000..0670503
--- /dev/null
+++ b/locale/en-us/dialog/en/another_shop_locations.dialog
@@ -0,0 +1,2 @@
+This store has more locations.
+There are more locations.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/ask_more.dialog b/locale/en-us/dialog/en/ask_more.dialog
index b2b8db3..ba35fb1 100644
--- a/locale/en-us/dialog/en/ask_more.dialog
+++ b/locale/en-us/dialog/en/ask_more.dialog
@@ -1 +1 @@
-Do you want to get another shop info?
\ No newline at end of file
+Do you want to get another store info?
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/by_time_sorting.dialog b/locale/en-us/dialog/en/by_time_sorting.dialog
new file mode 100644
index 0000000..f5299af
--- /dev/null
+++ b/locale/en-us/dialog/en/by_time_sorting.dialog
@@ -0,0 +1 @@
+Sorting stores by time.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/choose_selection.dialog b/locale/en-us/dialog/en/choose_selection.dialog
index 23ac161..01ba75b 100644
--- a/locale/en-us/dialog/en/choose_selection.dialog
+++ b/locale/en-us/dialog/en/choose_selection.dialog
@@ -1 +1 @@
-Do you want to select store by work hours or location?
\ No newline at end of file
+Do you want to sort stores by work hours or location?
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/closed_now.dialog b/locale/en-us/dialog/en/closed_now.dialog
deleted file mode 100644
index d095784..0000000
--- a/locale/en-us/dialog/en/closed_now.dialog
+++ /dev/null
@@ -1 +0,0 @@
-{{shop_name}} is closed now. Opens at {{open_time}}.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/closing_minutes.dialog b/locale/en-us/dialog/en/closing_minutes.dialog
index 46d9f8b..d17473d 100644
--- a/locale/en-us/dialog/en/closing_minutes.dialog
+++ b/locale/en-us/dialog/en/closing_minutes.dialog
@@ -1 +1 @@
-{{shop_name}} is open now. Closes in {{wait_min}} minutes.
\ No newline at end of file
+Closes in {{closing_minutes}} minutes.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/finished.dialog b/locale/en-us/dialog/en/finished.dialog
index 17ed73d..d570316 100644
--- a/locale/en-us/dialog/en/finished.dialog
+++ b/locale/en-us/dialog/en/finished.dialog
@@ -1 +1 @@
-Finished. Goodbye!
\ No newline at end of file
+Ok. Goodbye!
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/found_shop.dialog b/locale/en-us/dialog/en/found_shop.dialog
index d667791..2676dee 100644
--- a/locale/en-us/dialog/en/found_shop.dialog
+++ b/locale/en-us/dialog/en/found_shop.dialog
@@ -1 +1 @@
-I found {{name}} with hours {{hours}}. You can find this store on {{location}}.
\ No newline at end of file
+{{name}}, work hours are {{hours}}. You can find this store {{on}} {{location}}. Store is {{open}}.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/more_shops_info.dialog b/locale/en-us/dialog/en/more_shops_info.dialog
new file mode 100644
index 0000000..e9d0603
--- /dev/null
+++ b/locale/en-us/dialog/en/more_shops_info.dialog
@@ -0,0 +1 @@
+Do you want to get other {{shop_name}} locations info?
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/more_than_one.dialog b/locale/en-us/dialog/en/more_than_one.dialog
deleted file mode 100644
index 70532f4..0000000
--- a/locale/en-us/dialog/en/more_than_one.dialog
+++ /dev/null
@@ -1 +0,0 @@
-I found more than one shop in your request.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/no_shop_on_level.dialog b/locale/en-us/dialog/en/no_shop_on_level.dialog
index 69b5d6d..a6d1bb7 100644
--- a/locale/en-us/dialog/en/no_shop_on_level.dialog
+++ b/locale/en-us/dialog/en/no_shop_on_level.dialog
@@ -1 +1 @@
-There is no requested shop on your level. Here are all possible locations.
\ No newline at end of file
+There is no requested store on your level. Here are all possible locations.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/no_shop_request.dialog b/locale/en-us/dialog/en/no_shop_request.dialog
deleted file mode 100644
index 6ca56f4..0000000
--- a/locale/en-us/dialog/en/no_shop_request.dialog
+++ /dev/null
@@ -1 +0,0 @@
-Okay. I will stop mall parsing.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/open_now.dialog b/locale/en-us/dialog/en/open_now.dialog
deleted file mode 100644
index 3421d4c..0000000
--- a/locale/en-us/dialog/en/open_now.dialog
+++ /dev/null
@@ -1 +0,0 @@
-{{shop_name}} is open.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/opening_hours.dialog b/locale/en-us/dialog/en/opening_hours.dialog
index 3bcb8ce..10b12ce 100644
--- a/locale/en-us/dialog/en/opening_hours.dialog
+++ b/locale/en-us/dialog/en/opening_hours.dialog
@@ -1 +1 @@
-{{shop_name}} is closed now. Opens in {{wait_h}} hour and {{wait_min}} minutes'
\ No newline at end of file
+Opens in {{wait_h}} hour and {{wait_min}} minutes.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/opening_minutes.dialog b/locale/en-us/dialog/en/opening_minutes.dialog
index ce55fcc..af56a46 100644
--- a/locale/en-us/dialog/en/opening_minutes.dialog
+++ b/locale/en-us/dialog/en/opening_minutes.dialog
@@ -1 +1 @@
-{{shop_name}} is closed now. Opens in {{wait_min}} minutes.
\ No newline at end of file
+Opens in {{wait_min}} minutes.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/shop_by_floor.dialog b/locale/en-us/dialog/en/shop_by_floor.dialog
index 97c1ac0..09bcf05 100644
--- a/locale/en-us/dialog/en/shop_by_floor.dialog
+++ b/locale/en-us/dialog/en/shop_by_floor.dialog
@@ -1 +1 @@
-Do you want to get shop info by floor?
\ No newline at end of file
+Do you want to get store info by floor?
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/shop_not_found.dialog b/locale/en-us/dialog/en/shop_not_found.dialog
index 859f286..e395799 100644
--- a/locale/en-us/dialog/en/shop_not_found.dialog
+++ b/locale/en-us/dialog/en/shop_not_found.dialog
@@ -1,2 +1,2 @@
Sorry, this store doesn't exist in this mall. I am not sure I've understood what you said. Repeat, please.
-Sorry, I can not find this shop. I am not sure I've understood what you said. Repeat, please.
\ No newline at end of file
+Sorry, I can not find this store. I am not sure I've understood what you said. Repeat, please.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/shops_amount.dialog b/locale/en-us/dialog/en/shops_amount.dialog
new file mode 100644
index 0000000..2f4035c
--- /dev/null
+++ b/locale/en-us/dialog/en/shops_amount.dialog
@@ -0,0 +1 @@
+I found {{n}} {{loc_amount}} for {{store_name}}.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/shops_on_user_floor.dialog b/locale/en-us/dialog/en/shops_on_user_floor.dialog
new file mode 100644
index 0000000..f0ae44e
--- /dev/null
+++ b/locale/en-us/dialog/en/shops_on_user_floor.dialog
@@ -0,0 +1 @@
+I found {{n}} {{store_name}} stores on your level.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/start_parsing.dialog b/locale/en-us/dialog/en/start_parsing.dialog
deleted file mode 100644
index 4071f9b..0000000
--- a/locale/en-us/dialog/en/start_parsing.dialog
+++ /dev/null
@@ -1 +0,0 @@
-I am parsing shops and malls for your request.
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/stop.dialog b/locale/en-us/dialog/en/stop.dialog
deleted file mode 100644
index 2874c27..0000000
--- a/locale/en-us/dialog/en/stop.dialog
+++ /dev/null
@@ -1 +0,0 @@
-Do you want to exit the mall directory?
\ No newline at end of file
diff --git a/locale/en-us/dialog/en/which_floor.dialog b/locale/en-us/dialog/en/which_floor.dialog
deleted file mode 100644
index 4333de5..0000000
--- a/locale/en-us/dialog/en/which_floor.dialog
+++ /dev/null
@@ -1,3 +0,0 @@
-Which floor are you staying on?
-On which floor are you?
-what is your floor?
\ No newline at end of file
diff --git a/mall_cache.json b/mall_cache.json
new file mode 100644
index 0000000..e763be5
--- /dev/null
+++ b/mall_cache.json
@@ -0,0 +1 @@
+{"ABC Stores": [{"name": "ABC Stores", "hours": "9am – 9pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1615937914061-abcstores.png"}, {"name": "ABC Stores", "hours": "9am – 8pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1615937946329-abcstores.png"}], "Abercrombie & Fitch": [{"name": "Abercrombie & Fitch", "hours": "10am – 8pm", "location": "Level 3, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/stores/380.svg"}], "Aēsop": [{"name": "Aēsop", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1597705044914-aesop%20logo.png"}], "Agave And Vine": [{"name": "Agave And Vine", "hours": "11am – 10pm", "location": "Mall Level 2, in The Lanai", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/agave-vine-553x260-v21.png"}], "Ahi & Vegetable": [{"name": "Ahi & Vegetable", "hours": "9am – 8pm", "location": "Mall Level 2, in The Lanai", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Aja Sushi & Bento": [{"name": "Aja Sushi & Bento", "hours": "9am – 6pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Ala Moana Poi Bowl": [{"name": "Ala Moana Poi Bowl", "hours": "9am – 8pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Alexander Mcqueen": [{"name": "Alexander Mcqueen", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/alexander-mcqueen-logo-553x260-v1.png"}], "The Alley": [{"name": "The Alley", "hours": "11am – 9pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Aloha Dry Cleaners And Laundry": [{"name": "Aloha Dry Cleaners And Laundry", "hours": "11am – 7pm", "location": "Street Level 1, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1658192953454-ADCL%20logo.jpg"}], "Aloha Lane": [{"name": "Aloha Lane", "hours": "11am – 7pm", "location": "Street Level 1, near Old Navy", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/aloha-lane-logo-v1.png"}], "Al Phillips the Cleaner": [{"name": "Al Phillips the Cleaner", "hours": "6:30am – 8pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/Bunny-logo-553x260-v1.png"}], "American Eagle Outfitters": [{"name": "American Eagle Outfitters", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/467ed6fe0951a49572064dde41aca8da"}], "Amy's Hallmark": [{"name": "Amy's Hallmark", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/703.svg"}], "Anthropologie": [{"name": "Anthropologie", "hours": "11am – 7pm", "location": "Level 3, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/stores/2137020339.svg"}], "Apm Monaco": [{"name": "Apm Monaco", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1594332951496-APM%20Monaco%20Logo.jpg"}], "Apple": [{"name": "Apple", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/10327.svg"}], "AQUA BLU": [{"name": "AQUA BLU", "hours": "10am – 10pm", "location": "Level 3, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/aqua-blu-logo-553x260-v1.png"}], "Aritzia": [{"name": "Aritzia", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1610044848337-Aritzia-Logo-REGULAR-Final.jpg"}], "Around The Pearl": [{"name": "Around The Pearl", "hours": "11am – 2:30pm; 4:30pm – 8pm", "location": "Mall Level 2, near Target", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Assaggio": [{"name": "Assaggio", "hours": "11am – 2:30pm; 4:30pm – 8pm", "location": "Street Level 1, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "AT&T": [{"name": "AT&T", "hours": "10am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://placewise.imgix.net/images/api/retailhubjs/4a035067bbae402d523f151cc89c26fd"}], "Auntie Anne's": [{"name": "Auntie Anne's", "hours": "11am – 7pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Bae Beauty Hi": [{"name": "Bae Beauty Hi", "hours": "10am – 8pm", "location": "Street Level 1, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1615934194333-balenciaga-logo-1.png"}], "Balenciaga": [{"name": "Balenciaga", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1615934194333-balenciaga-logo-1.png"}], "Bally": [{"name": "Bally", "hours": "9:30am – 9pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/retailhubjs/97bd76329546dad6dc34754fd0a29365"}], "The Bar": [{"name": "The Bar", "hours": "12pm – 8pm", "location": "Inside Foodland Farms", "logo": "https://placewise.imgix.net/images/api/stores/2137060504.svg"}], "bareMinerals": [{"name": "bareMinerals", "hours": "11am – 7pm", "location": "Mall Level 2, near Target", "logo": "https://placewise.imgix.net/images/api/stores/2137060504.svg"}], "Barnes & Noble Booksellers": [{"name": "Barnes & Noble Booksellers", "hours": "10am – 9pm", "location": "Anchor Store", "logo": "https://placewise.imgix.net/images/api/stores/225.svg"}], "Barnes & Noble Café": [{"name": "Barnes & Noble Café", "hours": "10am – 9pm", "location": "Inside Barnes & Noble Booksellers", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Bath & Body Works": [{"name": "Bath & Body Works", "hours": "10am – 9pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/3.svg"}], "Ben Bridge Jeweler": [{"name": "Ben Bridge Jeweler", "hours": "10am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/retailhubjs/e5102aca8047112c6e61df58197158e8"}], "Ben Bridge Timeworks": [{"name": "Ben Bridge Timeworks", "hours": "10am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Big Island Candies": [{"name": "Big Island Candies", "hours": "10am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Bloomingdale's": [{"name": "Bloomingdale's", "hours": "11am – 8pm", "location": "Anchor Store", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/bloomingdales-logo-553x260-v1.png"}], "Blue Hawaii Lifestyle": [{"name": "Blue Hawaii Lifestyle", "hours": "11am – 6pm", "location": "Mall Level 2, near Target", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Body Play": [{"name": "Body Play", "hours": "11am – 7pm", "location": "Street Level 1", "logo": "https://placewise.imgix.net/images/api/stores/1921.svg"}, {"name": "Body Play", "hours": "11am – 7pm", "location": "Street Level 1", "logo": "https://placewise.imgix.net/images/api/stores/1921.svg"}], "The Body Shop": [{"name": "The Body Shop", "hours": "11am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "https://placewise.imgix.net/images/api/stores/1921.svg"}], "Bottega Veneta": [{"name": "Bottega Veneta", "hours": "11am – 7pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/bottega-veneta-logo-553x260-v1.png"}], "BoxLunch": [{"name": "BoxLunch", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://images.shoptopia.com/mcache/450/store/2137064563"}], "Brandy Melville": [{"name": "Brandy Melville", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/f9c0aef5eb4c2b858a76681d2419b21b"}], "Brighton Collectibles": [{"name": "Brighton Collectibles", "hours": "10am – 8pm", "location": "Level 3, near Target", "logo": "https://placewise.imgix.net/images/api/stores/5415.svg"}], "Brug": [{"name": "Brug", "hours": "9am – 6pm", "location": "Mall Level 2, in The Lanai", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "BRUG Hokkaido Bakery": [{"name": "BRUG Hokkaido Bakery", "hours": "8am – 6pm", "location": "Street Level 1, near Centerstage", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Brunello Cucinelli": [{"name": "Brunello Cucinelli", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1586484780201-BRUNELLO_08__PantCoolGrey10-resized.jpg"}], "Buffalo Wild Wings": [{"name": "Buffalo Wild Wings", "hours": "11am – 1am", "location": "Level 3, near Target", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Bulgari": [{"name": "Bulgari", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581816067950-Bulgari_header-logo.png"}], "Burberry": [{"name": "Burberry", "hours": "10am – 8pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/stores/1075.svg"}], "California Pizza Kitchen": [{"name": "California Pizza Kitchen", "hours": "11am – 10pm", "location": "Ho'okipa Terrace Upper Level 4, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Cartier": [{"name": "Cartier", "hours": "10am – 8pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/retailhubjs/304c1130bab67cd6cf6f894fe248214b"}], "CELINE": [{"name": "CELINE", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/celine-logo-553x260-v2.png"}], "Cellreon": [{"name": "Cellreon", "hours": "9:30am – 9pm", "location": "Mall Level 2, near Target", "logo": "https://placewise.imgix.net/images/api/stores/457.svg"}], "Centerstage": [{"name": "Centerstage", "hours": "9:30am – 9pm", "location": "Anchor Store", "logo": "https://placewise.imgix.net/images/api/stores/457.svg"}], "Champs Sports/Champs Women": [{"name": "Champs Sports/Champs Women", "hours": "10am – 8pm", "location": "Street Level 1, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/457.svg"}], "Chanel": [{"name": "Chanel", "hours": "10am – 8pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/retailhubjs/ce522af6364a85b0ad28b4dd9b6a41dc"}], "Chapel Hats": [{"name": "Chapel Hats", "hours": "11am – 7:30pm", "location": "Street Level 1, near Centerstage", "logo": "https://assets.digitalservices.ggp.com/content/dam/ggp-digital-assets/Images/Tenant-Images/Tenant-Logos/Chapel_Hats_553x260.png/jcr:content/renditions/original.png"}], "Charleys Philly Steaks": [{"name": "Charleys Philly Steaks", "hours": "11am – 7pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "CH Carolina Herrera": [{"name": "CH Carolina Herrera", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/carolina-herrera-logo-553x260-v1.png"}], "Cheeseburger Factory": [{"name": "Cheeseburger Factory", "hours": "11am – 7pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Chick-fil-A": [{"name": "Chick-fil-A", "hours": "10am – 8pm", "location": "Street Level 1, near Old Navy", "logo": "https://placewise.imgix.net/images/api/stores/779.svg"}, {"name": "Chick-fil-A", "hours": "10am – 8pm", "location": "Street Level 1, near Old Navy", "logo": "https://placewise.imgix.net/images/api/stores/779.svg"}], "CINNABON": [{"name": "CINNABON", "hours": "10am – 8pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Claire's": [{"name": "Claire's", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/5112.svg"}], "Coach": [{"name": "Coach", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/603.svg"}], "Cocolini": [{"name": "Cocolini", "hours": "7am – 8pm", "location": "Level 3, near Neiman Marcus", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "The Coffee Bean & Tea Leaf": [{"name": "The Coffee Bean & Tea Leaf", "hours": "7am – 8pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}, {"name": "The Coffee Bean & Tea Leaf", "hours": "10am – 8pm", "location": "Inside Foodland Farms", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Cole Haan": [{"name": "Cole Haan", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/9162.svg"}], "The Cookie Corner": [{"name": "The Cookie Corner", "hours": "10am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Crazy Shirts": [{"name": "Crazy Shirts", "hours": "11am – 7pm", "location": "Level 3, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/retailhubjs/c98cef49df3649a0a77e7b1b9281b8e0.jpeg"}], "Crispy Beef Jerky": [{"name": "Crispy Beef Jerky", "hours": "11am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1649363200135-HCBJ%201%20Color%20Black%20sm.jpg"}], "Crocs": [{"name": "Crocs", "hours": "11am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "https://placewise.imgix.net/images/api/stores/21370269690.svg"}], "Curry House CoCo Ichibanya": [{"name": "Curry House CoCo Ichibanya", "hours": "11am – 7pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Da Spot": [{"name": "Da Spot", "hours": "10am – 8pm", "location": "Mall Level 2, in The Lanai", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Dior": [{"name": "Dior", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1619635806579-dior%20logo.jpg"}], "Dior Cafe": [{"name": "Dior Cafe", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/dg-logo-553x260-v1.png"}], "Dolce&Gabbana": [{"name": "Dolce&Gabbana", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/dg-logo-553x260-v1.png"}], "E&K Jewelry": [{"name": "E&K Jewelry", "hours": "10am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "https://placewise.imgix.net/images/api/retailhubjs/ee6d3bd2687d1654da3d5d650c101214"}], "Ebar": [{"name": "Ebar", "hours": "8am – 9pm", "location": "Inside Nordstrom", "logo": "https://placewise.imgix.net/images/api/retailhubjs/ee6d3bd2687d1654da3d5d650c101214"}], "Eco Town": [{"name": "Eco Town", "hours": "10am – 8pm", "location": "Street Level 1, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1597707707663-eco%20town%20logo.jpg"}], "ELEVEN": [{"name": "ELEVEN", "hours": "Closed Today", "location": "Inside Foodland Farms", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Espresso Bar": [{"name": "Espresso Bar", "hours": "11am – 5pm", "location": "Inside Neiman Marcus", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Ewa Wing Stage": [{"name": "Ewa Wing Stage", "hours": "9:30am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1655846433321-Search%20For%20Snoopy-live%20AMC.png"}], "The Experience": [{"name": "The Experience", "hours": "9:30am – 7pm", "location": "Level 3, near Neiman Marcus", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1655846433321-Search%20For%20Snoopy-live%20AMC.png"}], "The Eye Gallery": [{"name": "The Eye Gallery", "hours": "9:30am – 7pm", "location": "Level 3, near Neiman Marcus", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/eyegallery.png"}], "Eztech Electronics": [{"name": "Eztech Electronics", "hours": "11am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/the-face-shop-logo.png"}], "The Face Shop": [{"name": "The Face Shop", "hours": "11am – 7pm", "location": "Mall Level 2, near Target", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/the-face-shop-logo.png"}], "Famous Footwear": [{"name": "Famous Footwear", "hours": "10am – 8pm", "location": "Street Level 1, near Old Navy", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1583269470608-FamousLogo_FullColor.png"}], "Fendi": [{"name": "Fendi", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/retailhubjs/5b05a987eadec96d8dc5be054703636c"}], "Foodland Farms": [{"name": "Foodland Farms", "hours": "6am – 9pm", "location": "Street Level 1, near Foodland Farms", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/foodland-farms-logo-553x260-v1.png"}], "Foot Locker": [{"name": "Foot Locker", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/320.svg"}], "Formidables Boutique": [{"name": "Formidables Boutique", "hours": "11am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/forty-carrots-logo-553x260-v1.png"}], "Forty Carrots": [{"name": "Forty Carrots", "hours": "11am – 8pm", "location": "Inside Bloomingdale's", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/forty-carrots-logo-553x260-v1.png"}], "Fossil": [{"name": "Fossil", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/5b3dd971f101b3f6b044403e4389e2eb"}], "Freaky Tiki Tropical Optical": [{"name": "Freaky Tiki Tropical Optical", "hours": "10am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581739164758-FREAKYTIKILogo.svg"}], "Gap": [{"name": "Gap", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/698.svg"}], "GapKids": [{"name": "GapKids", "hours": "10am – 9pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/2137026349.svg"}], "Gelato Bar": [{"name": "Gelato Bar", "hours": "10am – 9pm", "location": "Inside Nordstrom", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Genki Sushi": [{"name": "Genki Sushi", "hours": "11am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "GEN Korean BBQ House": [{"name": "GEN Korean BBQ House", "hours": "10am – 10pm", "location": "Ho'okipa Terrace Upper Level 4, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Genova International": [{"name": "Genova International", "hours": "11am – 7pm", "location": "Mall Level 2, near Target", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1649103585232-Genova%20Logo.jpg"}], "Giorgio Armani": [{"name": "Giorgio Armani", "hours": "11am – 7pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/stores/2137048880.svg"}], "GNC": [{"name": "GNC", "hours": "11am – 7pm", "location": "Street Level 1, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/1931.svg"}], "Golden Eye": [{"name": "Golden Eye", "hours": "10am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Goma Tei Ramen": [{"name": "Goma Tei Ramen", "hours": "11am – 9pm", "location": "Street Level 1, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "GRATiAE": [{"name": "GRATiAE", "hours": "9:30am – 5pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581818733224-GRATiEA_logo.png"}], "Gucci": [{"name": "Gucci", "hours": "11am – 7pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/stores/622.svg"}], "Guest Services": [{"name": "Guest Services", "hours": "11am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://placewise.imgix.net/images/api/stores/6401.svg"}], "H.I.S. Hawaii": [{"name": "H.I.S. Hawaii", "hours": "11am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://placewise.imgix.net/images/api/retailhubjs/62c4b28322444d5632cdbc12f740d89d.jpeg"}], "Häagen-Dazs": [{"name": "Häagen-Dazs", "hours": "11am – 8pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "https://placewise.imgix.net/images/api/retailhubjs/62c4b28322444d5632cdbc12f740d89d.jpeg"}], "Habitant": [{"name": "Habitant", "hours": "11am – 8pm", "location": "Inside Nordstrom", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581818789612-HappyWahine_Logo-1.png"}], "Happy Wahine Boutique": [{"name": "Happy Wahine Boutique", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581818789612-HappyWahine_Logo-1.png"}], "Harry Winston": [{"name": "Harry Winston", "hours": "10am – 8pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/retailhubjs/f5dd3d516082391544c8a2d18ac309c0.jpeg"}], "Hawaii's Finest": [{"name": "Hawaii's Finest", "hours": "10am – 8pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1654890093461-HIFI%20SIMPLE%20LOGO-01.png"}], "Hawaiian Island Creations": [{"name": "Hawaiian Island Creations", "hours": "11am – 7pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/Hawaiian-Island-Creations-logo.png"}], "Hawaii Vault": [{"name": "Hawaii Vault", "hours": "11am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/health-korea-logo-553x260-v1.png"}], "Health Korea": [{"name": "Health Korea", "hours": "11am – 7pm", "location": "Mall Level 2, near Target", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/health-korea-logo-553x260-v1.png"}], "Hermès": [{"name": "Hermès", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581739699694-hermes.svg"}], "Herve Chapelier": [{"name": "Herve Chapelier", "hours": "11am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/retailhubjs/6ff80c687b2ddc49ff6dc152447a91aa"}], "Hic Surf": [{"name": "Hic Surf", "hours": "10am – 8pm", "location": "Level 3, near Macy's", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/Hawaiian-Island-Creations-logo.png"}], "Hilo Hattie": [{"name": "Hilo Hattie", "hours": "11am – 7pm", "location": "Street Level 1, in the Diamond Head Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581739239969-Hilo_Hattie.svg"}], "Himalayan Kitchen": [{"name": "Himalayan Kitchen", "hours": "11am – 9pm", "location": "Street Level 1, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1614824768037-Hiro%20logo.png"}], "Hiro Systems Hawaii": [{"name": "Hiro Systems Hawaii", "hours": "8am – 7pm", "location": "Street Level 1, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1614824768037-Hiro%20logo.png"}], "HI Steaks": [{"name": "HI Steaks", "hours": "10am – 8pm", "location": "Inside Foodland Farms", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Hitea Cafe": [{"name": "Hitea Cafe", "hours": "10:30am – 7pm", "location": "Mall Level 2, in The Lanai", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Ho'āla Salon and Spa - Aveda": [{"name": "Ho'āla Salon and Spa - Aveda", "hours": "9am – 7pm", "location": "Level 3, near Neiman Marcus", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/hoala-logo-553x260-v1.png"}], "Hollister Co.": [{"name": "Hollister Co.", "hours": "10am – 8pm", "location": "Level 3, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/6328.svg"}], "Homecoming Honolulu": [{"name": "Homecoming Honolulu", "hours": "10am – 6pm", "location": "Level 3, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1659040688744-Honolulu%20Bistro%20Round%20Logo.jpg"}], "Honolulu Bistro": [{"name": "Honolulu Bistro", "hours": "10am – 6pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1659040688744-Honolulu%20Bistro%20Round%20Logo.jpg"}], "Honolulu Coffee Co.": [{"name": "Honolulu Coffee Co.", "hours": "10am – 8pm", "location": "Level 3, near Neiman Marcus", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}, {"name": "Honolulu Coffee Co.", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Honolulu Cookie Company": [{"name": "Honolulu Cookie Company", "hours": "10am – 8pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "https://placewise.imgix.net/images/api/retailhubjs/8971d844fa1e65263feb243f146c25b1"}], "Honolulu Satellite City Hall": [{"name": "Honolulu Satellite City Hall", "hours": "9am – 5pm", "location": "Street Level 1, near Macy's", "logo": "https://placewise.imgix.net/images/api/retailhubjs/dcc46eee9b06c66d4219fdd713599c57"}], "Hope And Henry": [{"name": "Hope And Henry", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/dcc46eee9b06c66d4219fdd713599c57"}], "Hot Topic": [{"name": "Hot Topic", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/801.svg"}], "Hublot": [{"name": "Hublot", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Illy Caffe": [{"name": "Illy Caffe", "hours": "10:30am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Island Brew Coffeehouse": [{"name": "Island Brew Coffeehouse", "hours": "7:30am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Island Crepes & Lemonade": [{"name": "Island Crepes & Lemonade", "hours": "10am – 7pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/island-crepes-lemonade-logo.png"}], "Island Slipper": [{"name": "Island Slipper", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/island-slipper-logo-553x260-v1.png"}], "Island Sole": [{"name": "Island Sole", "hours": "11am – 6pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581739204334-island_sole.svg"}], "Island Vintage Coffee": [{"name": "Island Vintage Coffee", "hours": "8am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "It'sugar": [{"name": "It'sugar", "hours": "11am – 8pm", "location": "Level 3, near Target", "logo": "https://placewise.imgix.net/images/api/retailhubjs/12afdfb4259bca255dfe83854328d3ff"}], "Jade Dynasty Seafood Restaurant": [{"name": "Jade Dynasty Seafood Restaurant", "hours": "10:30am – 9pm", "location": "Ho'okipa Terrace Upper Level 4, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Jamba Juice": [{"name": "Jamba Juice", "hours": "9am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}, {"name": "Jamba Juice", "hours": "10am – 9pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Jams World": [{"name": "Jams World", "hours": "10am – 9pm", "location": "Level 3, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/retailhubjs/d4da457fd8fcb5ca60a45ecf2a7b07d6"}], "Jeans Warehouse": [{"name": "Jeans Warehouse", "hours": "10am – 9pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/af7e23e5e3a899680c0ef823cb76e68f.png"}], "Jejubing Dessert Cafe": [{"name": "Jejubing Dessert Cafe", "hours": "12pm – 8pm", "location": "Street Level 1, near Centerstage", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Jimmy Choo": [{"name": "Jimmy Choo", "hours": "11am – 6pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1627608398102-Jimmy%20Choo%20Master%20Logo%20Black.jpg"}], "Johnny Was": [{"name": "Johnny Was", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/aa75ff1e567b611c008778387f8064ae"}], "Jollibee": [{"name": "Jollibee", "hours": "11am – 7pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Journeys": [{"name": "Journeys", "hours": "11am – 7pm", "location": "Level 3, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/2137048313.svg"}], "JTB 'OLI'OLI Station": [{"name": "JTB 'OLI'OLI Station", "hours": "8am – 5pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/jtb-logo-553x260-v1.png"}], "JTB USA": [{"name": "JTB USA", "hours": "8am – 5pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1593133191103-Jungle%20Fun%20Island%20Logo_RGB_No%20Blue%20Background.png"}], "Jungle Fun Island": [{"name": "Jungle Fun Island", "hours": "10am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1593133191103-Jungle%20Fun%20Island%20Logo_RGB_No%20Blue%20Background.png"}], "Kahala": [{"name": "Kahala", "hours": "11am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1663028129166-Kahala-Logo.jpg"}], "Kahulale'a": [{"name": "Kahulale'a", "hours": "11am – 7pm", "location": "Level 3, near Neiman Marcus", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1649875297885-logo.jpg"}], "Kamukura": [{"name": "Kamukura", "hours": "11am – 7pm", "location": "Mall Level 2, in The Lanai", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1649183466013-LOGO2.JPG"}], "Kate Spade New York": [{"name": "Kate Spade New York", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1615597970407-2017%20ksny_logo.jpg"}], "Kawaii Kawaii": [{"name": "Kawaii Kawaii", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1626229304345-27A5E5E6-79B5-4734-BFA6-D3142D155A51.png"}], "Kay Jewelers": [{"name": "Kay Jewelers", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/1755a594e1e40e37d73b3a06fd1c254e.png"}], "Koho": [{"name": "Koho", "hours": "11am – 6pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1635206131179-Koho_Logo.png%20(1).png"}], "Kpop Friends": [{"name": "Kpop Friends", "hours": "11am – 6pm", "location": "Mall Level 2, near Target", "logo": "https://placewise.imgix.net/images/api/stores/2137039695.svg"}], "L'Occitane": [{"name": "L'Occitane", "hours": "11am – 6pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/2137039695.svg"}], "Lacoste": [{"name": "Lacoste", "hours": "11am – 7pm", "location": "Level 3, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/retailhubjs/e2b15706500483595634fc39468a9b2a"}], "Laha'ole Designs": [{"name": "Laha'ole Designs", "hours": "10am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1663002609207-Logo.png"}], "Lahaina Chicken": [{"name": "Lahaina Chicken", "hours": "10am – 7pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Laine Honolulu": [{"name": "Laine Honolulu", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1636490297934-logo.png"}], "Land And Sea Golf": [{"name": "Land And Sea Golf", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1663198328472-LASG%20Logo.png"}], "The LEGO Store": [{"name": "The LEGO Store", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/2137023663.svg"}], "LensCrafters": [{"name": "LensCrafters", "hours": "9:30am – 8pm", "location": "Ho'okipa Terrace Upper Level 4, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1622760771134-LensCrafters_Logo_Black.jpg"}], "LeSportsac": [{"name": "LeSportsac", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/retailhubjs/65303a344cb9c77b79750d823c934872"}], "Lids": [{"name": "Lids", "hours": "11am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "https://placewise.imgix.net/images/api/stores/900.svg"}, {"name": "Lids", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/900.svg"}], "Liliha Bakery": [{"name": "Liliha Bakery", "hours": "7am – 8pm", "location": "Inside macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Little Café Siam": [{"name": "Little Café Siam", "hours": "9:30am – 9pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Local Motion": [{"name": "Local Motion", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/local-motion.png"}], "Locker Room by Lids": [{"name": "Locker Room by Lids", "hours": "11am – 7pm", "location": "Street Level 1, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/2137048183.svg"}], "Loewe": [{"name": "Loewe", "hours": "11am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/longines-logo-553x260-v1.png"}], "Longines": [{"name": "Longines", "hours": "11am – 7pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/longines-logo-553x260-v1.png"}], "Longs Drugs": [{"name": "Longs Drugs", "hours": "6am – 11pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/db6359b416299d2fedd19a061720335f.png"}], "Louis Vuitton": [{"name": "Louis Vuitton", "hours": "10am – 8pm", "location": "Level 3, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/stores/901.svg"}], "Love At Dawn": [{"name": "Love At Dawn", "hours": "10am – 6:30pm", "location": "Mall Level 2, near Target", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1617406505608-Main-PMS%20186-Horizontal.png"}], "LUCKY STRIKE SOCIAL": [{"name": "LUCKY STRIKE SOCIAL", "hours": "2pm – Midnight", "location": "Level 3, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1617406505608-Main-PMS%20186-Horizontal.png"}], "Lulu Hawaii": [{"name": "Lulu Hawaii", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/retailhubjs/c70a1f1f3f4b9d07fb6a8bb353871e7c"}], "Lululemon Athletica": [{"name": "Lululemon Athletica", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/c70a1f1f3f4b9d07fb6a8bb353871e7c"}], "LUPICIA": [{"name": "LUPICIA", "hours": "11am – 6pm", "location": "Street Level 1, near Centerstage", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/lupicia-logo-553x260-v1.png"}], "Lyca Mobile": [{"name": "Lyca Mobile", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/8cf9aebfb241b16fe45cc173ec966468.jpeg"}], "M.A.C": [{"name": "M.A.C", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/8cf9aebfb241b16fe45cc173ec966468.jpeg"}], "macy's": [{"name": "macy's", "hours": "9:30am – 8pm", "location": "Anchor Store", "logo": "https://placewise.imgix.net/images/api/stores/222.svg"}], "Madame Saigon Inc": [{"name": "Madame Saigon Inc", "hours": "10am – 8pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "https://placewise.imgix.net/images/api/retailhubjs/eee58f53e17a2ef6401fed29624e66c3.svg"}], "Madewell": [{"name": "Madewell", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/eee58f53e17a2ef6401fed29624e66c3.svg"}], "Madsci Lab": [{"name": "Madsci Lab", "hours": "10am – 8pm", "location": "Mall Level 2, near Target", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Mahaloha Burger": [{"name": "Mahaloha Burger", "hours": "10am – 8pm", "location": "Mall Level 2, in The Lanai", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Maison Margiela Paris": [{"name": "Maison Margiela Paris", "hours": "12pm – Midnight", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1662689149841-Maison_Margiela_logo.png"}], "Mai Tai's": [{"name": "Mai Tai's", "hours": "12pm – Midnight", "location": "Ho'okipa Terrace Upper Level 4, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1611958759854-Mai%20Tais%20logo%20translucent.png"}], "mālie": [{"name": "mālie", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/curbside-white.svg"}], "Mall Management": [{"name": "Mall Management", "hours": "10am – 7pm", "location": "Street Level 1, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Mama's Spaghetti House": [{"name": "Mama's Spaghetti House", "hours": "10am – 7pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Mama Pho": [{"name": "Mama Pho", "hours": "11am – 9pm", "location": "Ho'okipa Terrace Upper Level 4, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "MANAOLA HAWAII": [{"name": "MANAOLA HAWAII", "hours": "10am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/Manaola-logo.jpg"}], "Mana Sandwiches": [{"name": "Mana Sandwiches", "hours": "9am – 6pm", "location": "Mall Level 2, in The Lanai", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Mango Mango Dessert": [{"name": "Mango Mango Dessert", "hours": "11am – 9pm", "location": "Level 3, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Mani Pedi Spa": [{"name": "Mani Pedi Spa", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/curbside-white.svg"}], "Manna Myon": [{"name": "Manna Myon", "hours": "10am – 7:30pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Mariposa Restaurant": [{"name": "Mariposa Restaurant", "hours": "11:30am – 6pm", "location": "Inside Neiman Marcus", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/mariposa.png"}], "Marshalls": [{"name": "Marshalls", "hours": "9:30am – 9:30pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/3550.svg"}], "Martin & MacArthur": [{"name": "Martin & MacArthur", "hours": "11am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/curbside-white.svg"}], "Massage Palace": [{"name": "Massage Palace", "hours": "10am – 9pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1638411410564-logo_mauidivers_stacked_blue_02.png"}], "Maui Divers Jewelry": [{"name": "Maui Divers Jewelry", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1638411410564-logo_mauidivers_stacked_blue_02.png"}], "Meet Fresh": [{"name": "Meet Fresh", "hours": "12pm – 10pm", "location": "Street Level 1", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/mermaid-bar-logo.png"}], "Mermaid Bar": [{"name": "Mermaid Bar", "hours": "11am – 3:30pm", "location": "Mall Level 2, near Macy's", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/mermaid-bar-logo.png"}], "Michael Kors": [{"name": "Michael Kors", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/2137039706.svg"}], "Mika": [{"name": "Mika", "hours": "10am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Minamoto Kitchoan": [{"name": "Minamoto Kitchoan", "hours": "10am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Miu Miu": [{"name": "Miu Miu", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581815758592-miu_miu-logo.jpg"}], "Moncler": [{"name": "Moncler", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/moncler-logo-553x260-v1.png"}], "Montblanc": [{"name": "Montblanc", "hours": "11am – 7pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1663771368109-MB%20Logo%20with%20Snowcap%20Positive%20(1)1024_1.jpg"}], "Moomin Shop Hawaii": [{"name": "Moomin Shop Hawaii", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/curbside-white.svg"}], "Morphe": [{"name": "Morphe", "hours": "4pm – 9pm", "location": "Level 3, near Neiman Marcus", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/morphe-logo-553x260-v1.png"}], "Morton's The Steakhouse": [{"name": "Morton's The Steakhouse", "hours": "4pm – 9pm", "location": "Mall Level 2", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Mr. Cow Hawaii": [{"name": "Mr. Cow Hawaii", "hours": "9am – 7pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1651708815528-Mr%20Cow%20Logo%2010222.jpg"}], "Musubi Cafe Iyasume": [{"name": "Musubi Cafe Iyasume", "hours": "9am – 7pm", "location": "Mall Level 2, in The Lanai", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Nagasaki Champon By Ringer Hut": [{"name": "Nagasaki Champon By Ringer Hut", "hours": "11am – 7:30pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Na Hoku": [{"name": "Na Hoku", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/curbside-white.svg"}], "Naniwa-Ya Ramen": [{"name": "Naniwa-Ya Ramen", "hours": "9am – 9pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1644957597424-NR%20Logo-2.jpg"}], "Nature Republic": [{"name": "Nature Republic", "hours": "11am – 6pm", "location": "Level 3, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1644957597424-NR%20Logo-2.jpg"}], "Neiman Marcus": [{"name": "Neiman Marcus", "hours": "11am – 6pm", "location": "Anchor Store", "logo": "https://placewise.imgix.net/images/api/stores/1110.svg"}], "NET Electronics": [{"name": "NET Electronics", "hours": "8am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1647379072894-05-21%20Niu%20Health%20-%20Urgent%20Care%20Plus%20Sublogo%20v1%20-%20RGB%20Vertical.png"}], "Niu Health": [{"name": "Niu Health", "hours": "8am – 8pm", "location": "Mall Level 2, near Mauka Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1647379072894-05-21%20Niu%20Health%20-%20Urgent%20Care%20Plus%20Sublogo%20v1%20-%20RGB%20Vertical.png"}], "No'eau Designers": [{"name": "No'eau Designers", "hours": "10am – 8pm", "location": "Level 3", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1649184076308-Logo.jpg"}], "Nordstrom": [{"name": "Nordstrom", "hours": "10am – 9pm", "location": "Anchor Store", "logo": "https://assets.digitalservices.ggp.com/content/dam/ggp-digital-assets/Images/Tenant-Images/Tenant-Logos/nordstrom-bw-vector.svg/jcr:content/renditions/original.svg"}], "The North Face": [{"name": "The North Face", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/1139.svg"}], "Oakley": [{"name": "Oakley", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/curbside-white.svg"}], "Ocean Creations": [{"name": "Ocean Creations", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1598311501061-old-navy.jpg"}], "Ocean Queen": [{"name": "Ocean Queen", "hours": "10am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1598311501061-old-navy.jpg"}], "Old Navy": [{"name": "Old Navy", "hours": "10am – 8pm", "location": "Anchor Store", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1598311501061-old-navy.jpg"}], "Olive Garden": [{"name": "Olive Garden", "hours": "11am – 10pm", "location": "Ho'okipa Terrace Upper Level 4, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "OMEGA": [{"name": "OMEGA", "hours": "11am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "https://placewise.imgix.net/images/api/retailhubjs/e9ee6f494d191d393bec2902d357a454.jpeg"}], "PacSun": [{"name": "PacSun", "hours": "11am – 7pm", "location": "Level 3, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/2137031778.svg"}], "Panda Express": [{"name": "Panda Express", "hours": "10am – 8pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "PANDORA": [{"name": "PANDORA", "hours": "11am – 7pm", "location": "Mall Level 2, near Target", "logo": "https://placewise.imgix.net/images/api/stores/2137019886.svg"}], "Papaya": [{"name": "Papaya", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/25d55ffc0fcbe33387374071b4e8d064"}], "Paris Miki": [{"name": "Paris Miki", "hours": "10am – 7pm", "location": "Street Level 1, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581817440517-logo_basic_parismiki.png"}], "Patisserie La Palme D'or": [{"name": "Patisserie La Palme D'or", "hours": "9:30am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Pearl Plus": [{"name": "Pearl Plus", "hours": "Midnight – 10pm", "location": "Mall Level 2, near Target", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1622248999134-Logo.png"}], "Pink Box": [{"name": "Pink Box", "hours": "Midnight – 10pm", "location": "Mall Level 2, near Target", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1622248999134-Logo.png"}], "Pipe Dreams Surf Co": [{"name": "Pipe Dreams Surf Co", "hours": "Midnight – 10pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1622248999134-Logo.png"}], "Planet Fitness": [{"name": "Planet Fitness", "hours": "Midnight – 10pm", "location": "Street Level 1, near Saks Fifth Avenue OFF 5th", "logo": "https://placewise.imgix.net/images/api/retailhubjs/9c42bfed57038f5b63e356358cc4b08f"}], "Poke & Box": [{"name": "Poke & Box", "hours": "11am – 7pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Popoki Massage": [{"name": "Popoki Massage", "hours": "10am – 9pm", "location": "Street Level 1, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/curbside-white.svg"}], "Prada": [{"name": "Prada", "hours": "10am – 8pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/retailhubjs/2b9a3e6a7cacf9e5d627e0b11fd8a1ee.png"}, {"name": "Prada", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/2b9a3e6a7cacf9e5d627e0b11fd8a1ee.png"}], "Premier Barbershop": [{"name": "Premier Barbershop", "hours": "9:30am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "https://www.alamoanacenter.com/content/dam/rw-2/images/tenant-images/tenant-logos/premier-barbershop-logo-553x260-v2.png"}], "Pressed": [{"name": "Pressed", "hours": "8am – 9pm", "location": "Street Level 1, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Pups Of War": [{"name": "Pups Of War", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Raising Cane's": [{"name": "Raising Cane's", "hours": "9am – 8pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Rakuten Card Lounge": [{"name": "Rakuten Card Lounge", "hours": "10am – 6pm", "location": "Level 3, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Ramen Bario": [{"name": "Ramen Bario", "hours": "11am – 7pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Reformation": [{"name": "Reformation", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1658536892884-reformation-logo-01.jpg"}], "Reyn Spooner": [{"name": "Reyn Spooner", "hours": "10am – 8pm", "location": "Mall Level 2, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581739122871-ReynSpooner.svg"}], "Rimowa": [{"name": "Rimowa", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/rimowa-logo-553x260-v1.png"}], "Rip Curl": [{"name": "Rip Curl", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/251bf2d7769fa510c41dc011f2e80735.gif"}], "Rokkaku Hamakatsu": [{"name": "Rokkaku Hamakatsu", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Rolex": [{"name": "Rolex", "hours": "11am – 9pm", "location": "Mall Level 2, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1663101199998-Retailer_plaque_240x120-us.jpg"}], "Romano's Macaroni Grill": [{"name": "Romano's Macaroni Grill", "hours": "11am – 9pm", "location": "Ho'okipa Terrace Upper Level 4, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Ross Dress For Less": [{"name": "Ross Dress For Less", "hours": "9am – 10pm", "location": "Street Level 1, near Old Navy", "logo": "https://placewise.imgix.net/images/api/stores/4071.svg"}], "Royale": [{"name": "Royale", "hours": "11am – 8pm", "location": "Mall Level 2", "logo": "https://placewise.imgix.net/images/api/retailhubjs/d2d9f93c7bff2b67fb21f755a295d64d"}], "Ruscello": [{"name": "Ruscello", "hours": "11am – 8pm", "location": "Inside Nordstrom", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Saint Laurent": [{"name": "Saint Laurent", "hours": "11am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "https://assets.digitalservices.ggp.com/content/dam/ggp-digital-assets/Images/Tenant-Images/Tenant-Logos/saint-laurent-logo-v2.png/jcr:content/renditions/original.png"}], "Saks Fifth Avenue OFF 5TH": [{"name": "Saks Fifth Avenue OFF 5TH", "hours": "10am – 8pm", "location": "Anchor Store", "logo": "https://placewise.imgix.net/images/api/retailhubjs/b6635b648d8cd57d8dc8b58400a059f1.png"}], "Salvatore Ferragamo": [{"name": "Salvatore Ferragamo", "hours": "11am – 8pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://s3.amazonaws.com/placewisesitecontent/images/api/stores/2137031822.svg"}], "San Lorenzo Bikinis": [{"name": "San Lorenzo Bikinis", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/san-lorenzo-logo-553x260-v1.png"}], "Sears Appliances And Mattresses": [{"name": "Sears Appliances And Mattresses", "hours": "10am – 7pm", "location": "Street Level 1, near Saks Fifth Avenue OFF 5th", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1612300714395-Sears_Mattresses&AppliancesExteriorLogo_K.jpg"}], "Security Office": [{"name": "Security Office", "hours": "10am – 8pm", "location": "Street Level 1, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/242.svg"}], "See's Candies": [{"name": "See's Candies", "hours": "10am – 8pm", "location": "Street Level 1, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/242.svg"}], "Señor Pepé": [{"name": "Señor Pepé", "hours": "11am – 7pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1597707389497-senorpepe_logo.png"}], "Seoul Mix": [{"name": "Seoul Mix", "hours": "9am – 7pm", "location": "Mall Level 2, in The Lanai", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Sephora": [{"name": "Sephora", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/a11151fedd146744181733c3a955e72d.svg"}], "Sera's Surf 'N Shore": [{"name": "Sera's Surf 'N Shore", "hours": "11am – 6pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/shabuya-logo-553x260-v1.png"}], "Shabuya": [{"name": "Shabuya", "hours": "11am – 10pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/shabuya-logo-553x260-v1.png"}], "Sharetea": [{"name": "Sharetea", "hours": "10am – 7pm", "location": "Mall Level 2, in The Lanai", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Singmatei": [{"name": "Singmatei", "hours": "10am – 7pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Skechers": [{"name": "Skechers", "hours": "10am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/4287.svg"}], "Somisomi Soft Serve & Taiyaki": [{"name": "Somisomi Soft Serve & Taiyaki", "hours": "11am – 8pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Spectrum": [{"name": "Spectrum", "hours": "10am – 6pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/fcec6ed13969051a0fcc73bc7eb1d445"}], "Sports Box": [{"name": "Sports Box", "hours": "10am – 8pm", "location": "Mall Level 2, near Target", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1648154654467-Sports%20Box%20Logo.JPG"}], "SP Shoe Palace": [{"name": "SP Shoe Palace", "hours": "10am – 8pm", "location": "Level 3, near Macy's", "logo": "https://placewise.imgix.net/images/api/retailhubjs/f956de69f13fb5833f76d01b4c38c249"}], "Squishable": [{"name": "Squishable", "hours": "10am – 8pm", "location": "Level 3, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/retailhubjs/292148fdfa40fb57e2a05ff5660350a5"}], "Starbucks": [{"name": "Starbucks", "hours": "10am – 7pm", "location": "Street Level 1, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}, {"name": "Starbucks", "hours": "10am – 7pm", "location": "Inside macy's", "logo": "https://placewise.imgix.net/images/api/stores/5170.svg"}, {"name": "Starbucks", "hours": "10am – 7pm", "location": "Inside Target", "logo": "https://placewise.imgix.net/images/api/stores/5170.svg"}], "Steak & Fish Company": [{"name": "Steak & Fish Company", "hours": "10am – 7pm", "location": "Street Level 1, in Makai Market Food Court", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581818177874-Steak-and-Fish-Company-Logo.jpg"}], "Steak Teppei": [{"name": "Steak Teppei", "hours": "11am – 7pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Sugar Sugar Hawaii": [{"name": "Sugar Sugar Hawaii", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/584.svg"}], "Sunglass Hut": [{"name": "Sunglass Hut", "hours": "10am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://placewise.imgix.net/images/api/stores/584.svg"}, {"name": "Sunglass Hut", "hours": "8am – 6pm", "location": "Level 3, near Target", "logo": "https://placewise.imgix.net/images/api/stores/584.svg"}, {"name": "Sunglass Hut", "hours": "8am – 6pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/584.svg"}], "Sunrise Shack": [{"name": "Sunrise Shack", "hours": "8am – 6pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1622657582480-surfersbakery_logo%20(1).jpg"}], "Surfers Bakery": [{"name": "Surfers Bakery", "hours": "8am – 6pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1622657582480-surfersbakery_logo%20(1).jpg"}], "Swarovski": [{"name": "Swarovski", "hours": "11am – 7pm", "location": "Level 3, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/retailhubjs/8a9d9a28c3bb16f50cd4f075faad302d"}], "Swatch": [{"name": "Swatch", "hours": "10am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://placewise.imgix.net/images/api/retailhubjs/030b2d7cc3705f4f4945e31ebf8eb66d"}], "Sweet Honey Hawaii": [{"name": "Sweet Honey Hawaii", "hours": "11am – 3pm; 4pm – 9:30pm", "location": "Level 3, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Sxy Szechuan": [{"name": "Sxy Szechuan", "hours": "11am – 3pm; 4pm – 9:30pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "T&C Surf Designs": [{"name": "T&C Surf Designs", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/surf-designs-logo-553x260-v1.png"}], "Tanaka Of Tokyo": [{"name": "Tanaka Of Tokyo", "hours": "5pm – 9pm", "location": "Ho'okipa Terrace Upper Level 4, near Macy's", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Tanaka Ramen & Izakaya": [{"name": "Tanaka Ramen & Izakaya", "hours": "11am – 9:30pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Tanoa": [{"name": "Tanoa", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1652128897602-Logo%20and%20name%202.jpg"}], "Target": [{"name": "Target", "hours": "8am – 10pm", "location": "Anchor Store", "logo": "https://placewise.imgix.net/images/api/stores/2544.svg"}], "Teapresso Bar": [{"name": "Teapresso Bar", "hours": "10am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1662689771253-Teapresso%20Bar%20Logo.png"}], "Tech Armor": [{"name": "Tech Armor", "hours": "10am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://s3.amazonaws.com/placewisesitecontent/images/api/stores/2137046709.svg"}, {"name": "Tech Armor", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://s3.amazonaws.com/placewisesitecontent/images/api/stores/2137046709.svg"}], "Ted Baker London": [{"name": "Ted Baker London", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://s3.amazonaws.com/placewisesitecontent/images/api/stores/2137046709.svg"}], "Teppanyaki Farmer": [{"name": "Teppanyaki Farmer", "hours": "11am – 7pm", "location": "Mall Level 2, in The Lanai", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Territorial Savings Bank": [{"name": "Territorial Savings Bank", "hours": "9am – 5pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/territorial-bank-logo-553x260-v1.png"}], "Tesla": [{"name": "Tesla", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581739732249-Tesla.svg"}], "Tiffany & Co.": [{"name": "Tiffany & Co.", "hours": "11am – 7pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://placewise.imgix.net/images/api/stores/924.svg"}], "Tiger Sugar": [{"name": "Tiger Sugar", "hours": "11am – 9pm", "location": "Mall Level 2, near Target", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1650487282961-LOGO_直%20(1).png"}], "T-Mobile": [{"name": "T-Mobile", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/1250.svg"}], "Tod's": [{"name": "Tod's", "hours": "10am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1581817873976-Tods-Logo.jpg"}], "Tommy Bahama": [{"name": "Tommy Bahama", "hours": "10am – 8pm", "location": "Mall Level 2, near Target", "logo": "https://placewise.imgix.net/images/api/stores/02137020401.svg"}], "Tori Richard": [{"name": "Tori Richard", "hours": "11am – 7pm", "location": "Mall Level 2, near Macy's", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/tori-richard-logo-553x260-v1.png"}], "Tory Burch": [{"name": "Tory Burch", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/21370443810.svg"}], "TravisMathew": [{"name": "TravisMathew", "hours": "10am – 6pm", "location": "Mall Level 2, near Macy's", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1585179514507-True%20Friends%20logo.jpg"}], "True Friends": [{"name": "True Friends", "hours": "10am – 6pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1585179514507-True%20Friends%20logo.jpg"}], "TUMI": [{"name": "TUMI", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/3115.svg"}], "Two Palms": [{"name": "Two Palms", "hours": "11am – 7pm", "location": "Street Level 1, near Centerstage", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/curbside-white.svg"}], "U.S. Post Office": [{"name": "U.S. Post Office", "hours": "9am – 5pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/2137025526.svg"}], "Uniqlo": [{"name": "Uniqlo", "hours": "10am – 8pm", "location": "Mall Level 2, and Level 3 in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/2137047654.svg"}], "Valentino": [{"name": "Valentino", "hours": "11am – 7pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1582157782045-LOGO%20NEW%20JPG%20Valentino%20HIGH%20RES.gif"}], "Valextra": [{"name": "Valextra", "hours": "12pm – 6pm", "location": "Mall Level 2, near Neiman Marcus", "logo": "https://assets.digitalservices.ggp.com/content/dam/rw-2/images/tenant-images/tenant-logos/Valextra_Logo_553X260_v1.png#"}], "Vans": [{"name": "Vans", "hours": "11am – 7pm", "location": "Level 3, near Macy's", "logo": "https://placewise.imgix.net/images/api/stores/996.svg"}], "Victoria's Secret": [{"name": "Victoria's Secret", "hours": "10am – 8pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/588.svg"}], "Vim N\" Vigor Health & Fitness": [{"name": "Vim N\" Vigor Health & Fitness", "hours": "9am – 8pm", "location": "Street Level 1, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "The Vitamin Shoppe": [{"name": "The Vitamin Shoppe", "hours": "9am – 9pm", "location": "Street Level 1, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/stores/2137029560.svg"}], "Volcanoecigs": [{"name": "Volcanoecigs", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1602900084809-TTTAsset%202.png"}], "Volcom": [{"name": "Volcom", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1602900084809-TTTAsset%202.png"}], "Wahlburgers": [{"name": "Wahlburgers", "hours": "10:30am – 10pm", "location": "Mall Level 2, in the Ewa Wing", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Wai Nani Gifts": [{"name": "Wai Nani Gifts", "hours": "10am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1611953046696-2020-09-03.jpg"}], "Waterline Designs": [{"name": "Waterline Designs", "hours": "10am – 8pm", "location": "Street Level 1, near Centerstage", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1611953046696-2020-09-03.jpg"}], "Windsor": [{"name": "Windsor", "hours": "10am – 8pm", "location": "Level 3, in the Ewa Wing", "logo": "https://gizmostorageprod.blob.core.windows.net/tenant-logos/1611953046696-2020-09-03.jpg"}], "Xtreme 7d Dark Rides": [{"name": "Xtreme 7d Dark Rides", "hours": "3pm – 8pm", "location": "Ho'okipa Terrace Upper Level 4, near Macy's", "logo": "https://placewise.imgix.net/images/api/retailhubjs/0ec8202cdca398abb3e040cfb1de64a4"}], "Yomie's Rice X Yogurt": [{"name": "Yomie's Rice X Yogurt", "hours": "3pm – 8pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Yummy Korean BBQ": [{"name": "Yummy Korean BBQ", "hours": "10:30am – 8pm", "location": "Street Level 1, near Makai Market Food Court", "logo": "/etc/clientlibs/ggpcorp-malls/assets/directory/carry-out.svg"}], "Zagu": [{"name": "Zagu", "hours": "11am – 9pm", "location": "Street Level 1, near Centerstage", "logo": "https://placewise.imgix.net/images/api/stores/2137039918.svg"}], "ZARA": [{"name": "ZARA", "hours": "10am – 8pm", "location": "Anchor Store", "logo": "https://placewise.imgix.net/images/api/stores/2137039918.svg"}], "Zumiez": [{"name": "Zumiez", "hours": "11am – 7pm", "location": "Level 3, in the Ewa Wing", "logo": "https://placewise.imgix.net/images/api/retailhubjs/ff8a1fa869af18da93c8cfae76448959.jpeg"}]}
\ No newline at end of file
diff --git a/request_handling.py b/request_handling.py
index 049e56a..e193120 100644
--- a/request_handling.py
+++ b/request_handling.py
@@ -40,14 +40,12 @@
import os
import json
-from datetime import datetime
-
class RequestHandler():
caching_file = ''
-def find_cached_stores(user_request: str, url, file_path):
+def find_cached_stores(user_request: str, url, dir_path):
"""
Check shop name existence in cache keys
Args:
@@ -62,12 +60,13 @@ def find_cached_stores(user_request: str, url, file_path):
{"name": "ABS stores", "time": "8am-10pm", "location": "2 level"}
]
"""
- caching_file = file_path+'/cached_stores.json'
+ caching_file = os.path.join(dir_path, 'mall_cache.json')
if os.path.isfile(caching_file) == False:
LOG.info("Cache file doesn't exist")
- caching_stores_in_mall(file_path, url)
- return find_cached_stores(user_request, url, file_path)
+ caching_stores_in_mall(caching_file, url)
+ return find_cached_stores(user_request, url, caching_file)
else:
+ LOG.info("Cache file exists")
with open(caching_file, 'r', encoding='utf-8') as readfile:
data = json.load(readfile)
found_key = [key for key in data.keys()
@@ -77,12 +76,12 @@ def find_cached_stores(user_request: str, url, file_path):
if len(found_key) >=1 :
store_name = str(found_key[0])
LOG.info(f'Shop exists {data[store_name]}')
- return data[store_name], data
+ return data[store_name]
else:
LOG.info("Shop doesn't exist in cache")
- return None, data
+ return None
-def caching_stores_in_mall(file_path, url):
+def caching_stores_in_mall(caching_file, url):
"""
Creates caching file in the current class.
Creates empty dictionary for cache. Parses
@@ -102,7 +101,6 @@ def caching_stores_in_mall(file_path, url):
{"name": "ABS stores", "time": "8am-10pm", "location": "2 level"}
]}
"""
- caching_file = file_path+'/cached_stores.json'
LOG.info(f'caching_file {caching_file}')
shop_cache = {}
soup = parse(url)
@@ -141,26 +139,6 @@ def existing_lang_check(user_lang: str, url):
LOG.info('This language is not supported')
return False, link
-def curent_time_extraction():
- """
- Defines current time in utc timezone
- Format: hour:minutes part of day (1:23 pm)
-
- Returns:
- day_time (list): contains splited time
- numerals and part of the day
- day_time -> ['07:19', 'am']
- hour (int): current hour
- min (int): current minute
- """
- now = datetime.now().time().strftime("%I:%M %p")
- # now = datetime.today().strftime("%H:%M %p")
- LOG.info(f'now {now}')
- day_time = now.lower().split(' ')
- exact_time = day_time[0].split(':')
- hour, min = int(exact_time[0]), int(exact_time[1])
- return day_time, hour, min
-
def location_format(location):
"""
Finds all digits in store's location and
@@ -204,7 +182,7 @@ def shop_selection_by_floors(user_request, found_shops):
"""
shops_by_floor = []
for shop in found_shops:
- numbers = re.findall(r'\d+', shop['location'])
+ numbers = re.findall(r'\d+', shop[2]['location'])
if len(numbers) > 0:
numbers = numbers[0]
num = pronounce_number(int(numbers), ordinals=False)
@@ -227,7 +205,7 @@ def parse(url):
LOG.info("Failed url parsing")
-def get_shop_data(url, user_request, file_path):
+def get_shop_data(url, user_request, dir_path):
"""
Check existence of user's request store in cache
if shop was found returns list with shop info,
@@ -244,8 +222,7 @@ def get_shop_data(url, user_request, file_path):
: found_shops (list): found shops' info
"""
# search for store existence in cache
- LOG.info(file_path)
- found_shops, data = find_cached_stores(user_request, url, file_path)
+ found_shops = find_cached_stores(user_request, url, dir_path)
LOG.info(found_shops)
if found_shops:
LOG.info(f"found_shops: {found_shops}")
diff --git a/skill.json b/skill.json
index 1394d21..3fd5643 100644
--- a/skill.json
+++ b/skill.json
@@ -1,9 +1,9 @@
{
- "title": "{Malls parser skill neon}",
- "url": "https://github.com/NeonGeckoCom/skill-directory",
- "summary": "Skill for mall parsing",
- "short_description": "Skill for mall parsing",
- "description": "Skill parses mall web page and returns user name, location and work hours of requested shop, store",
+ "title": "{Mall guide skill neon}",
+ "url": "https://github.com/NeonGeckoCom/mall_guide_skill",
+ "summary": "Skill for guiding around the mall.",
+ "short_description": "Skill for guiding around the mall.",
+ "description": "Skill parses mall web page and returns user: name, location and work hours of requested shop, store",
"examples": [
"where is apple?",
"where can i find abc stores?"
@@ -43,7 +43,7 @@
"NeonGeckoCom",
"NeonMariia"
],
- "skillname": "skill-directory",
+ "skillname": "mall_guide_skill",
"authorname": "NeonGeckoCom",
"foldername": null
}
\ No newline at end of file
diff --git a/test/test_skill.py b/test/test_skill.py
index 411ad8f..cdf2cd3 100644
--- a/test/test_skill.py
+++ b/test/test_skill.py
@@ -64,24 +64,22 @@ def setUpClass(cls) -> None:
cls.skill.speak = Mock()
cls.skill.speak_dialog = Mock()
- # TODO: Put any skill method overrides here
+ # Override gui show to test passed arguments
+ cls.skill.gui.show_image = Mock()
def setUp(self):
self.skill.speak.reset_mock()
self.skill.speak_dialog.reset_mock()
- # TODO: Put any cleanup here that runs before each test case
-
@classmethod
def tearDownClass(cls) -> None:
shutil.rmtree(cls.test_fs)
def test_en_skill_init(self):
self.skill.ask_yesno = Mock(return_value="yes")
- self.skill.gui._pages2uri = Mock()
self.skill._start_mall_parser_prompt(
- Message('test', {'utterance': 'find ABC stores',
- 'shop': 'ABC stores',
+ Message('test', {'utterance': 'find Apple',
+ 'shop': 'Apple',
'lang': 'en-us'},
{'context_key': 'MallParsing'})
)
@@ -92,27 +90,17 @@ def test_en_skill_init(self):
{'context_key': 'MallParsing'})
self.skill.user_request_handling(message)
- def test_en_time_extraction(self):
- shop_info = [{'name': 'ABC Stores', 'hours': '9am – 9pm', 'location': 'Street Level 1, near Centerstage', 'logo': 'https://gizmostorageprod.blob.core.windows.net/tenant-logos/1615937914061-abcstores.png'},
- {'name': 'ABC Stores', 'hours': '10am – 8pm', 'location': 'Street Level 1, in the Ewa Wing', 'logo': 'https://gizmostorageprod.blob.core.windows.net/tenant-logos/1615937946329-abcstores.png'}]
- day_time, hour, min = ['10:15', 'am'], 10, 15
- result_shops = self.skill.open_shops_search(shop_info, day_time, hour, min)
- self.assertEqual(shop_info, result_shops)
-
- day_time, hour, min = ['9:15', 'am'], 9, 15
- result_shops = self.skill.open_shops_search(shop_info, day_time, hour, min)
- self.assertEqual(shop_info[0], result_shops[0])
+ def test_find_shop(self):
+ mall_link = "https://www.alamoanacenter.com/en/directory/"
- # def test_en_time_extraction(self):
- # shop_info = [{'name': 'ABC Stores', 'hours': '9am – 9pm', 'location': 'Street Level 1, near Centerstage', 'logo': 'https://gizmostorageprod.blob.core.windows.net/tenant-logos/1615937914061-abcstores.png'},
- # {'name': 'ABC Stores', 'hours': '10am – 8pm', 'location': 'Street Level 1, in the Ewa Wing', 'logo': 'https://gizmostorageprod.blob.core.windows.net/tenant-logos/1615937946329-abcstores.png'},
- # {'name': 'ABC Stores', 'hours': '10am – 9pm', 'location': 'Street Level 1, in the Ewa Wing', 'logo': 'https://gizmostorageprod.blob.core.windows.net/tenant-logos/1615937946329-abcstores.png'}]
+ user_request = 'starbucks'
+ new_count, user_request = self.skill.find_shop(user_request, mall_link)
+ self.assertEqual(new_count, 3)
- # day_time, hour, min = ['9:15', 'pm'], 9, 15
- # print(self.skill.time_calculation(shop_info, False, day_time, hour, min))
+ user_request = 'bubble'
+ new_count, user_request = self.skill.find_shop(user_request, mall_link)
+ self.assertEqual(new_count, 1)
- # day_time, hour, min = ['8:15', 'pm'], 8, 15
- # print(self.skill.time_calculation(shop_info, False, day_time, hour, min))
if __name__ == '__main__':
diff --git a/time_calculations_handling.py b/time_calculations_handling.py
new file mode 100644
index 0000000..f07cfbd
--- /dev/null
+++ b/time_calculations_handling.py
@@ -0,0 +1,121 @@
+# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework
+# All trademark and other rights reserved by their respective owners
+# Copyright 2008-2022 Neongecko.com Inc.
+# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds,
+# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo
+# BSD-3 License
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from neon_utils.skills.neon_skill import LOG
+from datetime import datetime
+import re
+
+def current_time_extraction():
+ """
+ Defines current time in utc timezone
+ Format: hour:minutes part of day (1:23 pm)
+
+ Returns:
+ day_time (list): contains splited time
+ numerals and part of the day
+ day_time -> ['07:19', 'am']
+ hour (int): current hour
+ min (int): current minute
+ """
+ now = datetime.now().time().strftime("%I:%M %p")
+ # now = datetime.today().strftime("%H:%M %p")
+ LOG.info(f'now {now}')
+ day_time = now.lower().split(' ')
+ exact_time = day_time[0].split(':')
+ hour, min = int(exact_time[0]), int(exact_time[1])
+ return day_time, hour, min
+
+
+def time_calculation(shop_info, day_time, hour, min):
+ """
+ Calculates time difference between user's current time
+ and shop working hours.
+ If 'open' argument is True:
+ If user one hour or less before closing: speaks how
+ many minutes left. Speaks shop info.
+ Else speaks corresponging dialog.
+ Speaks shop info.
+ If 'open' argument is False:
+ Speaks corresponding dialog.
+ If user is one hour or less before opening hours
+ speaks how much time is left for waiting.
+ If user's time is 'am' and user is before opening
+ hours, speaks how many hours and minutes left
+ waiting.
+ If user's time is evening (pm) speaks when the shop
+ opens in the morning.
+ Speaks shop info.
+ Args:
+ shop_info (list): found shops on user's request
+ open (boolean): True - if shop is open
+ day_time (str): user's current day time (am|pm)
+ hour (int): user's current hour
+ min (int): user's current minute
+ Returns:
+ 3, None (to ask for another shop info)
+ Examples:
+ work time 9am-10pm
+ user's time 8am
+ Prompt: 'Shop is closed now. Opens in 1 hour'
+ """
+ open_shops = []
+ closed_shops = []
+ for shop in shop_info:
+ work_time = shop['hours']
+ normalized_time = re.findall(r'(\d+)[am|pm]', work_time)
+ open_time = int(normalized_time[0])
+ close_time = int(normalized_time[1])
+ LOG.info(f'work_time {work_time}')
+ # time left
+ wait_h = open_time - hour - 1
+ wait_min = 60 - min
+ if day_time[1] == 'pm' and 0 < (close_time - hour) <= 1:
+ shop['open'] = 'open'
+ open_shops.append([wait_min, None, shop])
+ elif day_time[1] == 'pm' and close_time > hour:
+ shop['open'] = 'open'
+ open_shops.append([None, None, shop])
+ elif day_time[1] == 'am' and open_time <= hour:
+ shop['open'] = 'open'
+ open_shops.append([None, None, shop])
+ elif day_time[1] == 'am' and hour < open_time:
+ if wait_h == 0:
+ shop['open'] = 'closed'
+ closed_shops.append([wait_min, None, shop])
+ else:
+ shop['open'] = 'closed'
+ closed_shops.append([wait_min, wait_h, shop])
+ elif day_time[1] == 'pm' and hour >= close_time:
+ shop['open'] = 'closed'
+ closed_shops.append([None, open_time, shop])
+ LOG.info(f'found shops open: {open_shops}')
+ LOG.info(f'found shops closed: {closed_shops}')
+ found_shops = open_shops + closed_shops
+ LOG.info(f'open + closed: {found_shops}')
+ return found_shops
+