diff --git a/.gitignore b/.gitignore
index f85c6b1..fb6e305 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,5 @@
-config.py
\ No newline at end of file
+*/node_modules/
+libinfo-scraper/
+!libinfo-scraper/__pycache__
+!libinfo-scraper/easy_install.py
+!libinfo-scraper/libinfo-scraper.py
\ No newline at end of file
diff --git a/busyness/__init__.py b/busyness/__init__.py
new file mode 100644
index 0000000..8b8fd6c
--- /dev/null
+++ b/busyness/__init__.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from .crawler import run
+from .crawler import get_populartimes
+
+import logging
+logging.getLogger(__name__).addHandler(logging.NullHandler())
+
+"""
+
+ENTRY POINT
+
+"""
+
+
+def get(api_key, types, p1, p2, n_threads=20, radius=180, all_places=False):
+ """
+ :param api_key: str; api key from google places web service
+ :param types: [str]; placetypes
+ :param p1: (float, float); lat/lng of the south-west delimiting point
+ :param p2: (float, float); lat/lng of the north-east delimiting point
+ :param n_threads: int; number of threads to use
+ :param radius: int; meters;
+ :param all_places: bool; include/exclude places without populartimes
+ :return: see readme
+ """
+ params = {
+ "API_key": api_key,
+ "radius": radius,
+ "type": types,
+ "n_threads": n_threads,
+ "all_places": all_places,
+ "bounds": {
+ "lower": {
+ "lat": min(p1[0], p2[0]),
+ "lng": min(p1[1], p2[1])
+ },
+ "upper": {
+ "lat": max(p1[0], p2[0]),
+ "lng": max(p1[1], p2[1])
+ }
+ }
+ }
+
+ return run(params)
+
+
+def get_id(api_key, place_id):
+ """
+ retrieves the current popularity for a given place
+ :param api_key:
+ :param place_id:
+ :return: see readme
+ """
+ return get_populartimes(api_key, place_id)
diff --git a/busyness/__pycache__/crawler.cpython-37.pyc b/busyness/__pycache__/crawler.cpython-37.pyc
new file mode 100644
index 0000000..f65139b
Binary files /dev/null and b/busyness/__pycache__/crawler.cpython-37.pyc differ
diff --git a/busyness/crawler.py b/busyness/crawler.py
new file mode 100644
index 0000000..850c4f9
--- /dev/null
+++ b/busyness/crawler.py
@@ -0,0 +1,558 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import calendar
+import datetime
+import json
+import logging
+import math
+import re
+import ssl
+import threading
+import urllib.request
+import urllib.parse
+from time import sleep, time
+from queue import Queue
+
+# import requests
+from botocore.vendored import requests
+
+# from geopy import Point
+# from geopy.distance import vincenty, VincentyDistance
+
+# urls for google api web service
+BASE_URL = "https://maps.googleapis.com/maps/api/place/"
+RADAR_URL = BASE_URL + "radarsearch/json?location={},{}&radius={}&types={}&key={}"
+NEARBY_URL = BASE_URL + "nearbysearch/json?location={},{}&radius={}&types={}&key={}"
+DETAIL_URL = BASE_URL + "details/json?placeid={}&key={}"
+
+# user agent for populartimes request
+USER_AGENT = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
+ "Chrome/54.0.2840.98 Safari/537.36"}
+
+
+class PopulartimesException(Exception):
+ """Exception raised for errors in the input.
+
+ Attributes:
+ expression -- input expression in which the error occurred
+ message -- explanation of the error
+ """
+
+ def __init__(self, expression, message):
+ self.expression = expression
+ self.message = message
+
+
+def rect_circle_collision(rect_left, rect_right, rect_bottom, rect_top, circle_x, circle_y, radius):
+ # returns true iff circle intersects rectangle
+
+ def clamp(val, min, max):
+ # limits value to the range min..max
+ if val < min:
+ return min
+ if val > max:
+ return max
+ return val
+
+ # Find the closest point to the circle within the rectangle
+ closest_x = clamp(circle_x, rect_left, rect_right);
+ closest_y = clamp(circle_y, rect_bottom, rect_top);
+
+ # Calculate the distance between the circle's center and this closest point
+ dist_x = circle_x - closest_x;
+ dist_y = circle_y - closest_y;
+
+ # If the distance is less than the circle's radius, an intersection occurs
+ dist_sq = (dist_x * dist_x) + (dist_y * dist_y);
+
+ return dist_sq < (radius * radius);
+
+def cover_rect_with_cicles(w, h, r):
+ """
+ fully cover a rectangle of given width and height with
+ circles of radius r. This algorithm uses a hexagonal
+ honeycomb pattern to cover the area.
+
+ :param w: width of rectangle
+ :param h: height of reclangle
+ :param r: radius of circles
+ :return: list of circle centers (x,y)
+ """
+
+ #initialize result list
+ res = []
+
+ # horizontal distance between circle centers
+ x_dist = math.sqrt(3) * r
+ # vertical distance between circle centers
+ y_dist = 1.5 * r
+ # number of circles per row (different for even/odd rows)
+ cnt_x_even = math.ceil(w / x_dist)
+ cnt_x_odd = math.ceil((w - x_dist/2) / x_dist) + 1
+ # number of rows
+ cnt_y = math.ceil((h-r) / y_dist) + 1
+
+ y_offs = 0.5 * r
+ for y in range(cnt_y):
+ if y % 2 == 0:
+ # shift even rows to the right
+ x_offs = x_dist/2
+ cnt_x = cnt_x_even
+ else:
+ x_offs = 0
+ cnt_x = cnt_x_odd
+
+ for x in range(cnt_x):
+ res.append((x_offs + x*x_dist, y_offs + y*y_dist))
+
+ # top-right circle is not always required
+ if res and not rect_circle_collision(0, w, 0, h, res[-1][0], res[-1][1], r):
+ res = res[0:-1]
+
+ return res
+
+def get_circle_centers(b1, b2, radius):
+ """
+ the function covers the area within the bounds with circles
+
+ :param b1: south-west bounds [lat, lng]
+ :param b2: north-east bounds [lat, lng]
+ :param radius: specified radius, adapt for high density areas
+ :return: list of circle centers that cover the area between lower/upper
+ """
+
+ sw = Point(b1)
+ ne = Point(b2)
+
+ # north/east distances
+ dist_lat = vincenty(Point(sw[0], sw[1]), Point(ne[0], sw[1])).meters
+ dist_lng = vincenty(Point(sw[0], sw[1]), Point(sw[0], ne[1])).meters
+
+ circles = cover_rect_with_cicles(dist_lat, dist_lng, radius)
+ cords = [
+ VincentyDistance(meters=c[0])
+ .destination(
+ VincentyDistance(meters=c[1])
+ .destination(point=sw, bearing=90),
+ bearing=0
+ )[:2]
+ for c in circles
+ ]
+
+ return cords
+
+
+def worker_radar():
+ """
+ worker that gets coordinates of queue and starts radar search
+ :return:
+ """
+ while True:
+ item = q_radar.get()
+ get_radar(item)
+ q_radar.task_done()
+
+
+def get_radar(item):
+ _lat, _lng = item["pos"]
+
+ # places - nearby search
+ # https://developers.google.com/places/web-service/search?hl=en#PlaceSearchRequests
+ radar_str = NEARBY_URL.format(
+ _lat, _lng, params["radius"], "|".join(params["type"]), params["API_key"]
+ )
+
+ # is this a next page request?
+ if item["res"] > 0:
+ # possibly wait remaining time until next_page_token becomes valid
+ min_wait = 2 # wait at least 2 seconds before the next page request
+ sec_passed = time() - item["last_req"]
+ if sec_passed < min_wait:
+ sleep(min_wait - sec_passed)
+ radar_str += "&pagetoken=" + item["next_page_token"]
+
+ resp = json.loads(requests.get(radar_str, auth=('user', 'pass')).text)
+ check_response_code(resp)
+
+ radar = resp["results"]
+
+ item["res"] += len(radar)
+ if item["res"] >= 60:
+ logging.warning("Result limit in search radius reached, some data may get lost")
+
+ bounds = params["bounds"]
+
+ # retrieve google ids for detail search
+ for place in radar:
+
+ geo = place["geometry"]["location"]
+ if bounds["lower"]["lat"] <= geo["lat"] <= bounds["upper"]["lat"] \
+ and bounds["lower"]["lng"] <= geo["lng"] <= bounds["upper"]["lng"]:
+ # this isn't thread safe, but we don't really care,
+ # since in worst case a set entry is simply overwritten
+ g_places[place["place_id"]] = place
+
+ # if there are more results, schedule next page requests
+ if "next_page_token" in resp:
+ item["next_page_token"] = resp["next_page_token"]
+ item["last_req"] = time()
+ q_radar.put(item)
+
+
+def worker_detail():
+ """
+ worker that gets item of queue and starts detailed data retrieval
+ :return:
+ """
+ while True:
+ item = q_detail.get()
+ get_detail(item)
+ q_detail.task_done()
+
+
+def get_popularity_for_day(popularity,name=""):
+ """
+ Returns popularity for day
+ :param popularity:
+ :return:
+ """
+
+ # Initialize empty matrix with 0s
+ pop_json = [[0 for _ in range(24)] for _ in range(7)]
+ wait_json = [[0 for _ in range(24)] for _ in range(7)]
+
+ for day in popularity:
+
+ day_no, pop_times = day[:2]
+
+ if pop_times:
+ for hour_info in pop_times:
+
+ hour = hour_info[0]
+ pop_json[day_no - 1][hour] = hour_info[1]
+
+ # check if the waiting string is available and convert no minutes
+ if len(hour_info) > 5:
+ wait_digits = re.findall(r'\d+', hour_info[3])
+
+ if len(wait_digits) == 0:
+ wait_json[day_no - 1][hour] = 0
+ elif "min" in hour_info[3]:
+ wait_json[day_no - 1][hour] = int(wait_digits[0])
+ elif "hour" in hour_info[3]:
+ wait_json[day_no - 1][hour] = int(wait_digits[0]) * 60
+ else:
+ wait_json[day_no - 1][hour] = int(wait_digits[0]) * 60 + int(wait_digits[1])
+
+ # day wrap
+ if hour_info[0] == 23:
+ day_no = day_no % 7 + 1
+
+ ret_popularity = [
+
+ {
+ "day": list(calendar.day_name)[d],
+ "busyness": pop_json[d]
+ } for d in range(7)
+ ]
+
+
+ # waiting time only if applicable
+ ret_wait = [
+ {
+ "name": list(calendar.day_name)[d],
+ "data": wait_json[d]
+ } for d in range(7)
+ ] if any(any(day) for day in wait_json) else []
+
+ # {"name" : "monday", "data": [...]} for each weekday as list
+ return ret_popularity, ret_wait
+
+
+def index_get(array, *argv):
+ """
+ checks if a index is available in the array and returns it
+ :param array: the data array
+ :param argv: index integers
+ :return: None if not available or the return value
+ """
+
+ try:
+
+ for index in argv:
+ array = array[index]
+
+ return array
+
+ # there is either no info available or no popular times
+ # TypeError: rating/rating_n/populartimes wrong of not available
+ except (IndexError, TypeError):
+ return None
+
+
+def add_optional_parameters(detail_json, detail, rating, rating_n, popularity, current_popularity, time_spent):
+ """
+ check for optional return parameters and add them to the result json
+ :param detail_json:
+ :param detail:
+ :param rating:
+ :param rating_n:
+ :param popularity:
+ :param current_popularity:
+ :param time_spent:
+ :return:
+ """
+ # print(popularity)
+ if rating:
+ detail_json["rating"] = rating
+ elif "rating" in detail:
+ detail_json["rating"] = detail["rating"]
+
+ if rating_n:
+ detail_json["rating_n"] = rating_n
+
+ if "international_phone_number" in detail:
+ detail_json["international_phone_number"] = detail["international_phone_number"]
+
+ if current_popularity:
+ detail_json["current_popularity"] = current_popularity
+
+ if popularity:
+ popularity, wait_times = get_popularity_for_day(popularity)
+
+ detail_json["populartimes"] = popularity
+
+ if wait_times:
+ detail_json["time_wait"] = wait_times
+
+ if time_spent:
+ detail_json["time_spent"] = time_spent
+
+ return detail_json
+
+
+def get_populartimes_from_search(place_identifier):
+ """
+ request information for a place and parse current popularity
+ :param place_identifier: name and address string
+ :return:
+ """
+ # print("place identifier={}".format(place_identifier))
+ params_url = {
+ "tbm": "map",
+ "tch": 1,
+ "hl": "en",
+ "q": urllib.parse.quote_plus(place_identifier),
+ "pb": "!4m12!1m3!1d4005.9771522653964!2d-122.42072974863942!3d37.8077459796541!2m3!1f0!2f0!3f0!3m2!1i1125!2i976"
+ "!4f13.1!7i20!10b1!12m6!2m3!5m1!6e2!20e3!10b1!16b1!19m3!2m2!1i392!2i106!20m61!2m2!1i203!2i100!3m2!2i4!5b1"
+ "!6m6!1m2!1i86!2i86!1m2!1i408!2i200!7m46!1m3!1e1!2b0!3e3!1m3!1e2!2b1!3e2!1m3!1e2!2b0!3e3!1m3!1e3!2b0!3e3!"
+ "1m3!1e4!2b0!3e3!1m3!1e8!2b0!3e3!1m3!1e3!2b1!3e2!1m3!1e9!2b1!3e2!1m3!1e10!2b0!3e3!1m3!1e10!2b1!3e2!1m3!1e"
+ "10!2b0!3e4!2b1!4b1!9b0!22m6!1sa9fVWea_MsX8adX8j8AE%3A1!2zMWk6Mix0OjExODg3LGU6MSxwOmE5ZlZXZWFfTXNYOGFkWDh"
+ "qOEFFOjE!7e81!12e3!17sa9fVWea_MsX8adX8j8AE%3A564!18e15!24m15!2b1!5m4!2b1!3b1!5b1!6b1!10m1!8e3!17b1!24b1!"
+ "25b1!26b1!30m1!2b1!36b1!26m3!2m2!1i80!2i92!30m28!1m6!1m2!1i0!2i0!2m2!1i458!2i976!1m6!1m2!1i1075!2i0!2m2!"
+ "1i1125!2i976!1m6!1m2!1i0!2i0!2m2!1i1125!2i20!1m6!1m2!1i0!2i956!2m2!1i1125!2i976!37m1!1e81!42b1!47m0!49m1"
+ "!3b1"
+ }
+
+ search_url = "https://www.google.de/search?" + "&".join(k + "=" + str(v) for k, v in params_url.items())
+ logging.info("searchterm: " + search_url)
+
+ # noinspection PyUnresolvedReferences
+ gcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+
+ resp = urllib.request.urlopen(urllib.request.Request(url=search_url, data=None, headers=USER_AGENT),
+ context=gcontext)
+ data = resp.read().decode('utf-8').split('/*""*/')[0]
+
+ # find eof json
+ jend = data.rfind("}")
+ if jend >= 0:
+ data = data[:jend + 1]
+
+ jdata = json.loads(data)["d"]
+ jdata = json.loads(jdata[4:])
+
+ # get info from result array, has to be adapted if backend api changes
+ info = index_get(jdata, 0, 1, 0, 14)
+
+ rating = index_get(info, 4, 7)
+ rating_n = index_get(info, 4, 8)
+
+ popular_times = index_get(info, 84, 0)
+
+ # current_popularity is also not available if popular_times isn't
+ current_popularity = index_get(info, 84, 7, 1)
+
+ time_spent = index_get(info, 117, 0)
+
+ # extract wait times and convert to minutes
+ if time_spent:
+
+ nums = [float(f) for f in re.findall(r'\d*\.\d+|\d+', time_spent.replace(",", "."))]
+ contains_min, contains_hour = "min" in time_spent, "hour" in time_spent or "hr" in time_spent
+
+ time_spent = None
+
+ if contains_min and contains_hour:
+ time_spent = [nums[0], nums[1] * 60]
+ elif contains_hour:
+ time_spent = [nums[0] * 60, (nums[0] if len(nums) == 1 else nums[1]) * 60]
+ elif contains_min:
+ time_spent = [nums[0], nums[0] if len(nums) == 1 else nums[1]]
+
+ time_spent = [int(t) for t in time_spent]
+
+ return rating, rating_n, popular_times, current_popularity, time_spent
+
+
+def get_detail(place_id):
+ """
+ loads data for a given area
+ :return:
+ """
+ global results
+
+ # detail_json = get_populartimes(params["API_key"], place_id)
+ detail_json = get_populartimes_by_detail(params["API_key"], g_places[place_id])
+
+ if params["all_places"] or "populartimes" in detail_json:
+ results.append(detail_json)
+
+
+def get_populartimes(api_key, place_id):
+ """
+ sends request to detail to get a search string
+ and uses standard proto buffer to get additional information
+ on the current status of popular times
+ :return: json details
+ """
+
+ # places api - detail search
+ # https://developers.google.com/places/web-service/details?hl=de
+ detail_str = DETAIL_URL.format(place_id, api_key)
+ resp = json.loads(requests.get(detail_str, auth=('user', 'pass')).text)
+ check_response_code(resp)
+ detail = resp["result"]
+ print(place_id,detail["name"])
+ return get_populartimes_by_detail(api_key, detail)
+
+
+def get_populartimes_by_detail(api_key, detail):
+ # print(detail)
+ address = detail["formatted_address"] if "formatted_address" in detail else detail["vicinity"]
+
+ place_identifier = "{} {}".format(detail["name"], address)
+
+ detail_json = {
+ "id": detail["place_id"],
+ "name": detail["name"],
+ "address": address,
+ "types": detail["types"],
+ "coordinates": detail["geometry"]["location"]
+ }
+
+ detail_json = add_optional_parameters(detail_json, detail, *get_populartimes_from_search(place_identifier))
+
+ return detail_json
+
+
+def get_populartimes_by_detail_no_key(place_identifier):
+ detail_json = {
+ "id": detail["place_id"],
+ "name": detail["name"],
+ "address": address,
+ "types": detail["types"],
+ "coordinates": detail["geometry"]["location"]
+ }
+
+ detail_json = add_optional_parameters(detail_json, detail, *get_populartimes_from_search(place_identifier))
+
+ return detail_json
+
+
+def check_response_code(resp):
+ """
+ check if query quota has been surpassed or other errors occured
+ :param resp: json response
+ :return:
+ """
+ if resp["status"] == "OK" or resp["status"] == "ZERO_RESULTS":
+ return
+
+ if resp["status"] == "REQUEST_DENIED":
+ raise PopulartimesException("Google Places " + resp["status"],
+ "Request was denied, the API key is invalid.")
+
+ if resp["status"] == "OVER_QUERY_LIMIT":
+ raise PopulartimesException("Google Places " + resp["status"],
+ "You exceeded your Query Limit for Google Places API Web Service, "
+ "check https://developers.google.com/places/web-service/usage "
+ "to upgrade your quota.")
+
+ if resp["status"] == "INVALID_REQUEST":
+ raise PopulartimesException("Google Places " + resp["status"],
+ "The query string is malformed, "
+ "check if your formatting for lat/lng and radius is correct.")
+
+ if resp["status"] == "INVALID_REQUEST":
+ raise PopulartimesException("Google Places " + resp["status"],
+ "The query string is malformed, "
+ "check if your formatting for lat/lng and radius is correct.")
+
+ if resp["status"] == "NOT_FOUND":
+ raise PopulartimesException("Google Places " + resp["status"],
+ "The place ID was not found and either does not exist or was retired.")
+
+ raise PopulartimesException("Google Places " + resp["status"],
+ "Unidentified error with the Places API, please check the response code")
+
+
+def run(_params):
+ """
+ wrap execution logic in method, for later external call
+ :return:
+ """
+ global params, g_places, q_radar, q_detail, results
+
+ start = datetime.datetime.now()
+
+ # shared variables
+ params = _params
+ q_radar, q_detail = Queue(), Queue()
+ g_places, results = dict(), list()
+
+ logging.info("Adding places to queue...")
+
+ # threading for radar search
+ for i in range(params["n_threads"]):
+ t = threading.Thread(target=worker_radar)
+ t.daemon = True
+ t.start()
+
+ # cover search area with circles
+ bounds = params["bounds"]
+ for lat, lng in get_circle_centers([bounds["lower"]["lat"], bounds["lower"]["lng"]], # southwest
+ [bounds["upper"]["lat"], bounds["upper"]["lng"]], # northeast
+ params["radius"]):
+ q_radar.put(dict(pos=(lat, lng), res=0))
+
+ q_radar.join()
+ logging.info("Finished in: {}".format(str(datetime.datetime.now() - start)))
+
+ logging.info("{} places to process...".format(len(g_places)))
+
+ # threading for detail search and popular times
+ for i in range(params["n_threads"]):
+ t = threading.Thread(target=worker_detail)
+ t.daemon = True
+ t.start()
+
+ for g_place_id in g_places:
+ q_detail.put(g_place_id)
+
+ q_detail.join()
+ logging.info("Finished in: {}".format(str(datetime.datetime.now() - start)))
+
+ return results
diff --git a/busyness/crawler.pyc b/busyness/crawler.pyc
new file mode 100644
index 0000000..c73160b
Binary files /dev/null and b/busyness/crawler.pyc differ
diff --git a/busyness/lambda_function.py b/busyness/lambda_function.py
new file mode 100644
index 0000000..cf6bd32
--- /dev/null
+++ b/busyness/lambda_function.py
@@ -0,0 +1,65 @@
+import crawler
+
+import boto3
+import json
+
+
+
+
+# ChIJq6qqIYq8woARFNfDahGA4Js
+
+def lambda_handler(event, context):
+ # Get the service resource.
+ dynamodb = boto3.resource('dynamodb')
+
+ # Instantiate a table resource object without actually
+ # creating a DynamoDB table. Note that the attributes of this table
+ # are lazy-loaded: a request is not made nor are the attribute
+ # values populated until the attributes
+ # on the table resource are accessed or its load() method is called.
+ table = dynamodb.Table('lib_hours')
+
+ # google does not have data for the commented out libraries
+ libraries={
+ 'Powell Library':'Powell Library',
+ 'Charles E. Young Research Library': 'Research Library (Charles E. Young)',
+ 'The Study at Hedrick':'The Study at Hedrick',
+ 'UCLA Music Library':'Music Library',
+ 'Rosenfeld Library':'Management Library (Eugene and Maxine Rosenfeld)',
+ 'UCLA Science and Engineering Library':'Science and Engineering Library'
+ # 'Hugh & Hazel Darling Law Library',
+ # 'UCLA Louise M. Darling Biomedical Library',
+ # 'Rudolph East Asian Library',
+ # 'Arts Library',
+ # 'Southern Regional Library Facility'
+ }
+ print(libraries)
+ for Library in libraries.keys():
+
+ print(Library)
+ rating, rating_n, popular_times, current_popularity, time_spent= crawler.get_populartimes_from_search(Library)
+ weekly_busyness=crawler.get_popularity_for_day(popular_times)[0]
+
+ if current_popularity ==None:
+ current_popularity=0
+
+
+ # popularity={
+ # "name":libraries[Library],
+ # "weekly_busyness" :weekly_busyness,
+ # "current_busyness":current_popularity
+ # }
+ # table.update_item(
+ # Item=popularity
+ # )
+ response = table.update_item(
+ Key={"name":libraries[Library]},
+ UpdateExpression="set weekly_busyness = :wb, current_busyness=:cb",
+ ExpressionAttributeValues={
+ ':wb': weekly_busyness,
+ ':cb': current_popularity,
+ },
+ ReturnValues="UPDATED_NEW"
+ )
+ print(response);
+lambda_handler(0,0)
\ No newline at end of file
diff --git a/classroomScraper/index.js b/classroomScraper/index.js
new file mode 100644
index 0000000..d7eb445
--- /dev/null
+++ b/classroomScraper/index.js
@@ -0,0 +1,519 @@
+var AWS = require("aws-sdk");
+AWS.config.update({ region: "us-east-1" });
+//var docClient = new AWS.DynamoDB.DocumentClient();
+
+//RDS
+// var pg = require('pg');
+// var con = mysql.createConnection({
+// host: 'studysmart-db.chpjzhfmtelr.us-west-1.rds.amazonaws.com',
+// user: 'studyroot',
+// password: 'studysmart-db',
+// port: 5432,
+// database: 'mydb'
+// });
+
+// con.connect(function(err) {
+// if (err) throw err;
+// console.log("Connected!");
+// });
+
+var pg = require('pg');
+var conString = "postgres://studyroot:studysmart-db@studysmart-db.chpjzhfmtelr.us-west-1.rds.amazonaws.com:5432/mydb";
+
+var client = new pg.Client(conString);
+client.connect(err => {
+ if (err) {
+ console.error('Postgres connection error', err.stack);
+ } else {
+ console.log('connected to Postgres database');
+ }
+});
+
+const requestPromise = require("request-promise");
+const moment = require("moment");
+const jsdom = require("jsdom");
+const { JSDOM } = jsdom;
+
+var res = [];
+var queryFinished = false;
+
+exports.handler = async function (event) {
+ "use strict";
+
+ // Constants
+ const mainURL =
+ "https://www.registrar.ucla.edu/desktopmodules/ClassRoomSearch/api/webapi/GetClassroomItems";
+ const classroomURL =
+ "https://www.registrar.ucla.edu/desktopmodules/ClassRoomSearch/api/webapi/GetCalendarEvents";
+ const academicCalendarURL =
+ "https://www.registrar.ucla.edu/Calendars/Annual-Academic-Calendar";
+
+ // set the current term based on today's date
+ function parseDate(date, year)
+ {
+ let ret = year.concat("-");
+ if(typeof(date) === 'string')
+ {
+ let tokens = date.split(", ");
+ if(tokens.length != 2)
+ {
+ console.log("could not parse date, datestring was not in correct format");
+ process.exit(1);
+ }
+ else
+ {
+ let tokens2 = tokens[1].split(" ");
+ if(tokens2.length != 2)
+ {
+ console.log("could not parse date, datestring was not in correct format");
+ process.exit(1);
+ }
+ else
+ {
+ switch(tokens2[0])
+ {
+ case "January":
+ ret += "01-";
+ break;
+ case "February":
+ ret += "02-";
+ break;
+ case "March":
+ ret += "03-";
+ break;
+ case "April":
+ ret += "04-";
+ break;
+ case "May":
+ ret += "05-";
+ break;
+ case "June":
+ ret += "06-";
+ break;
+ case "July":
+ ret += "07-";
+ break;
+ case "August":
+ ret += "08-";
+ break;
+ case "September":
+ ret += "09-";
+ break;
+ case "October":
+ ret += "10-";
+ break;
+ case "Novemeber":
+ ret += "11-";
+ break;
+ case "December":
+ ret += "12-";
+ break;
+ default:
+ console.log("could not parse date, month is invalid");
+ process.exit(1);
+ }
+
+ if(tokens2[1].length == 1)
+ ret += "0";
+ ret = ret.concat(tokens2[1]);
+ return ret;
+ }
+ }
+ }
+ else
+ {
+ console.log("could not parse date, parameter was not a string");
+ process.exit(1);
+ }
+ }
+
+ async function getCurrentTerm()
+ {
+ console.log("getting current term");
+ console.log("trying to send request to", academicCalendarURL);
+ async function handleRequest(options, delay)
+ {
+ let a = new Promise(function(resolve, reject) {
+ setTimeout(() => resolve("done"), delay);
+ });
+
+ await a;
+
+ return requestPromise(options);
+ }
+
+ let options = {
+ method: "GET",
+ url: academicCalendarURL,
+ json: true
+ };
+
+ var results = await handleRequest(options, 1000);
+ const dom = new JSDOM(results);
+
+ let currDate = new Date();
+ let year = currDate.getFullYear() - 2000;
+ // we get all the elements where id ends with (for example) 2019-20 and 2020-21
+ let academicYears = dom.window.document.querySelectorAll(`[id$='20${year - 1}-${year}'][id^='lt'], [id$='20${year}-${year + 1}'][id^='lt']`);
+
+ // then we loop through the two academic years and we find the dates that "quarter begins" corresponds to
+ // first maintain a counter to determine what year each date corresponds to
+ // each time, it only outputs 8 values, because we are searching through two academic years
+ // 2 academic years * (3 dates for each regular quarter + 1 date for summer session) = 8 dates
+ let count = 0;
+ let dates = [];
+ for(let i = 0; i < academicYears.length; i++)
+ {
+ let rows = academicYears[i].querySelectorAll("td");
+ for(let j = 0; j < rows.length; j++)
+ {
+ let text = rows[j].textContent;
+ if(text.match(/Quarter begins*/) || text.match(/Summer session begins*/))
+ {
+ switch(count)
+ {
+ case 0:
+ // we'll discard the date from the previous year
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ // we only push the dates that pertain to the current year
+ dates.push(new Date(parseDate(rows[j + 1].textContent, "20" + year)));
+ break;
+ case 5:
+ case 6:
+ case 7:
+ // we'll also discared the dates in the next year
+ break;
+ default:
+ // this is just to check if we've outputted the right number of dates.
+ // if there were too many, then we know there was an error
+ console.log("error: too many \"quarter begins\" or \"summer session begins\" dates were outputted");
+ }
+
+ count++;
+ }
+ }
+ }
+
+ // our dates list should contain 4 dates in the same calendar year - the start of each quarter: Winter, Spring, Summer Sessions, Fall
+ let num = -1;
+ for(let i = 0; i < dates.length; i++)
+ {
+ if(currDate.getTime() < dates[i].getTime())
+ {
+ num = i;
+ break;
+ }
+ }
+
+ if(num == -1)
+ num = 4;
+
+ switch(num)
+ {
+ case 0:
+ return (year - 1) + "F";
+ case 1:
+ return year + "W";
+ case 2:
+ return year + "S";
+ case 3:
+ return year + "1";
+ case 4:
+ return year + "F";
+ }
+ }
+
+ let currentTerm = await getCurrentTerm();
+ console.log("the current term is", currentTerm);
+
+ // Helper functions
+ function processClassroomJson(buildingClassroom) {
+ return {
+ building: buildingClassroom.value.slice(0, 8),
+ room: buildingClassroom.value.substr(9),
+ buildingName: buildingClassroom.label.slice(0, 8).trim(),
+ roomName: buildingClassroom.label.substr(9).trim()
+ };
+ }
+
+ function processClassTimeObject(buildingArray, classNameTime) {
+ if (classNameTime.enroll_total === 0) return buildingArray;
+
+ let processedObject = {
+ day: "",
+ start: "",
+ end: ""
+ };
+
+ if (classNameTime.start.substr(0, 9) != "2014-11-1") {
+ processedObject.day = "Varies";
+ processedObject.start = classNameTime.start.substr(0, 5);
+ processedObject.end = classNameTime.end.substr(0, 5);
+ } else {
+ let startTime = moment(classNameTime.start);
+ let endTime = moment(classNameTime.end);
+
+ processedObject.day = startTime.format("d");
+ processedObject.start = startTime.format("HH:mm");
+ processedObject.end = endTime.format("HH:mm");
+ }
+ buildingArray.push(processedObject);
+ return buildingArray;
+ }
+
+ async function getClassroomTimes(buildingRoomObject, callback) {
+ let options = {
+ method: "GET",
+ url: classroomURL,
+ qs: {
+ term: currentTerm,
+ building: buildingRoomObject.building,
+ room: buildingRoomObject.room
+ },
+ json: true
+ };
+
+ var finishedRequest = false;
+ while(!finishedRequest)
+ {
+ try
+ {
+ var body = await handleRequest(options, 100);
+ finishedRequest = true;
+ }
+ catch(e)
+ {
+ console.log("RequestError for getting ", buildingRoomObject.building, buildingRoomObject.room);
+ console.log(e.message);
+ console.log("trying again...")
+ }
+ }
+
+ body = body.reduce(processClassTimeObject, []);
+
+ let finalClassroomObject = {
+ building: buildingRoomObject.buildingName,
+ room: buildingRoomObject.roomName,
+ classTimes: body
+ };
+ let ClassroomAvailabilities = getAvailableTimes(finalClassroomObject);
+ callback(ClassroomAvailabilities);
+ }
+
+ function tomins(timeString) {
+ let timeObj = stoiParser(timeString);
+ return timeObj['hour'] * 60 + timeObj['minutes'];
+ }
+
+ function stoiParser(timeString) {
+ return {
+ 'hour': parseInt(timeString.substring(0, 2)),
+ 'minutes': parseInt(timeString.substring(3))
+ };
+ }
+
+ function getAvailableTimes(classroomTimeObject) {
+ let inverseObject = {};
+ let inverseArray = [];
+
+ inverseObject.building = classroomTimeObject.building;
+ inverseObject.room = classroomTimeObject.room;
+ inverseObject.classTimes = [];
+ inverseObject.class_key = "";
+ let timesByDay = { '1': [], '2': [], '3': [], '4': [], '5': [], 'Varies': [] };
+ let inverseTimesByDay = { '1': [], '2': [], '3': [], '4': [], '5': [], 'Varies': [] }
+ for (let timeSlot of classroomTimeObject.classTimes) {
+ timesByDay[timeSlot.day].push(timeSlot);
+ }
+ for (let d in timesByDay) {
+ let s = '08:00';
+ for (let slot of timesByDay[d]) {
+ if (tomins(slot['start']) - tomins(s) > 15) {
+ inverseTimesByDay[d].push({ 'day': d, 'start': s, 'end': slot['start'] });
+ }
+ s = slot['end'];
+ }
+ inverseTimesByDay[d].push({ 'day': d, 'start': s, 'end': '22:00' });
+ }
+
+ for (let d in inverseTimesByDay) {
+ for (let slot of inverseTimesByDay[d]) {
+ let NewTimeSlot = {}
+ NewTimeSlot.day = d;
+ NewTimeSlot.start = tomins(slot['start']);
+ NewTimeSlot.end = tomins(slot['end']);
+ NewTimeSlot.room = inverseObject.room;
+ NewTimeSlot.building = inverseObject.building;
+ inverseArray.push(NewTimeSlot);
+ }
+ }
+
+ return inverseArray;
+ }
+
+ // Wrapper function for sending requests, with delay parameter.
+ async function handleRequest(options, delay)
+ {
+ let a = new Promise(function(resolve, reject) {
+ setTimeout(() => resolve("done"), delay);
+ });
+
+ await a;
+
+ return requestPromise(options);
+ }
+
+ async function queryWrapper(sql)
+ {
+ await client.query(sql);
+ return true;
+ }
+
+ async function continueExec()
+ {
+ // Here is the trick, wait until var callbackCount is set number of callback functions.
+ if (done_count > 0)
+ {
+ return false;
+ }
+
+ // Finally, do what you need
+ console.log("got each classroom's schedule");
+ let st = ""
+ res.forEach(function (resp) {
+ if (resp.day != "Varies" && resp.start < resp.end) {
+
+ let day = resp.day.toString();
+ let start = resp.start.toString();
+ let end = resp.end.toString();
+ let room = resp.room;
+ let building = resp.building;
+ st += "(" + day + "," + start + "," + end + "," + "'" + room + "'" + "," + "'" + building + "'" + "),\n";
+
+ }
+ })
+
+ // Run the query in the database.
+ let deleteSQL = "DELETE FROM classroom_availabilities;";
+ let insertSQL = "INSERT INTO classroom_availabilities (day, start_time, end_time, room, building) VALUES" + st.substring(0, st.length - 2);
+ try
+ {
+ console.log("deleting existing data from database...");
+ await queryWrapper(deleteSQL);
+ let delay = new Promise(function(resolve, reject) {
+ setTimeout(() => resolve("done"), 1000);
+ });
+ await delay;
+ console.log("inserting into the database...");
+ queryFinished = await queryWrapper(insertSQL);
+ }
+ catch(err)
+ {
+ console.log(err.stack);
+ queryFinished = true;
+ }
+
+ return true;
+ }
+
+ function isUnusedRoom(crAvailList)
+ {
+ if(crAvailList.length == 6
+ && crAvailList[0].day == '1'
+ && crAvailList[1].day == '2'
+ && crAvailList[2].day == '3'
+ && crAvailList[3].day == '4'
+ && crAvailList[4].day == '5'
+ && crAvailList[5].day == 'Varies')
+ return true;
+
+ return false;
+ }
+
+ // try to get classrooms for the current quarter
+ let options = {
+ method: "GET",
+ url: mainURL,
+ json: true
+ };
+
+ // Send a request to get all classrooms for the current quarter.
+ var resolved = false;
+ var delay = 2000;
+ while(!resolved)
+ {
+ console.log("trying to send request to ", options.url);
+ try
+ {
+ var body = await handleRequest(options, delay);
+ resolved = true;
+ }
+ catch(e)
+ {
+ console.log("error sending request to ", options.url, ": ", e.message);
+ console.log("trying to send it again...");
+ }
+ }
+
+ console.log("got classrooms");
+
+ // For each classroom, send a request to get its availability.
+ console.log("trying to send request to server for each classroom's availability...");
+ let classrooms = body.map(processClassroomJson);
+ let done_count = classrooms.length;
+
+ classrooms.forEach(async function (classroom) {
+ await getClassroomTimes(classroom, function (response) {
+ // Here you have access to your variable
+ if(!isUnusedRoom(response))
+ res = res.concat(response)
+ done_count -= 1;
+ })
+ });
+
+ // We must wait until all the requests for the classrooms have returned.
+ // The while loop will continue to call "continueExec()" until the variable
+ // done_count reaches 0. The "continueExec()" function includes the query
+ // that is run in the database.
+ while(1)
+ {
+ let a = new Promise(function(resolve, reject) {
+ setTimeout(() => resolve("done"), 2000);
+ });
+
+ await a;
+
+ console.log("waiting for all classroom requests to return...");
+ if(await continueExec())
+ break;
+ }
+
+ // Wait for the query to finish running and then break.
+ while(1)
+ {
+ if(queryFinished)
+ {
+ console.log("finished.");
+ break;
+ }
+
+ let a = new Promise(function(resolve, reject) {
+ setTimeout(() => resolve("done"), 2000);
+ });
+
+ await a;
+ console.log("waiting for query to finish...");
+ }
+};
+
+//uncomment out this part if you want to run it locally
+/*try {
+ exports.handler({});
+} catch (e) {
+ console.log("error");
+ // Deal with the fact the chain failed
+}*/
diff --git a/classroomScraper/package-lock.json b/classroomScraper/package-lock.json
new file mode 100644
index 0000000..cb6618f
--- /dev/null
+++ b/classroomScraper/package-lock.json
@@ -0,0 +1,1197 @@
+{
+ "name": "classroommetadata",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@types/concat-stream": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz",
+ "integrity": "sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0=",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/form-data": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz",
+ "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/node": {
+ "version": "10.14.21",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.21.tgz",
+ "integrity": "sha512-nuFlRdBiqbF+PJIEVxm2jLFcQWN7q7iWEJGsBV4n7v1dbI9qXB8im2pMMKMCUZe092sQb5SQft2DHfuQGK5hqQ=="
+ },
+ "@types/qs": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.5.3.tgz",
+ "integrity": "sha512-Jugo5V/1bS0fRhy2z8+cUAHEyWOATaz4rbyLVvcFs7+dXp5HfwpEwzF1Q11bB10ApUqHf+yTauxI0UXQDwGrbA=="
+ },
+ "abab": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz",
+ "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg=="
+ },
+ "acorn": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
+ "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg=="
+ },
+ "acorn-globals": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz",
+ "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==",
+ "requires": {
+ "acorn": "^7.1.1",
+ "acorn-walk": "^7.1.1"
+ }
+ },
+ "acorn-walk": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz",
+ "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ=="
+ },
+ "ajv": {
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+ "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "aws-sdk": {
+ "version": "2.544.0",
+ "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.544.0.tgz",
+ "integrity": "sha512-wwiBJgAUGKXY/xoCSrUXVZnNtefoH3YcPwGxQrQXOIDnLMQ32yh/SWc52qmwdxA7WJzpTcIj8y+5keH3P1LYaw==",
+ "requires": {
+ "buffer": "4.9.1",
+ "events": "1.1.1",
+ "ieee754": "1.1.13",
+ "jmespath": "0.15.0",
+ "querystring": "0.2.0",
+ "sax": "1.2.1",
+ "url": "0.10.3",
+ "uuid": "3.3.2",
+ "xml2js": "0.4.19"
+ },
+ "dependencies": {
+ "uuid": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+ }
+ }
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+ },
+ "aws4": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
+ },
+ "base64-js": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "bignumber.js": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz",
+ "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ=="
+ },
+ "bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
+ },
+ "browser-process-hrtime": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
+ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
+ },
+ "buffer": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
+ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4",
+ "isarray": "^1.0.0"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
+ },
+ "buffer-writer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
+ "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw=="
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "cssom": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
+ "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw=="
+ },
+ "cssstyle": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz",
+ "integrity": "sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==",
+ "requires": {
+ "cssom": "~0.3.6"
+ },
+ "dependencies": {
+ "cssom": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
+ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
+ }
+ }
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "data-urls": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
+ "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==",
+ "requires": {
+ "abab": "^2.0.3",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^8.0.0"
+ }
+ },
+ "decimal.js": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz",
+ "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw=="
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "domexception": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
+ "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==",
+ "requires": {
+ "webidl-conversions": "^5.0.0"
+ },
+ "dependencies": {
+ "webidl-conversions": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
+ "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
+ }
+ }
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "escodegen": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz",
+ "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==",
+ "requires": {
+ "esprima": "^4.0.1",
+ "estraverse": "^4.2.0",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1",
+ "source-map": "~0.6.1"
+ }
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+ },
+ "estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
+ },
+ "esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
+ },
+ "events": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
+ "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "get-port": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz",
+ "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw="
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+ },
+ "har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "requires": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "html-encoding-sniffer": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
+ "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==",
+ "requires": {
+ "whatwg-encoding": "^1.0.5"
+ }
+ },
+ "http-basic": {
+ "version": "8.1.3",
+ "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",
+ "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==",
+ "requires": {
+ "caseless": "^0.12.0",
+ "concat-stream": "^1.6.2",
+ "http-response-object": "^3.0.1",
+ "parse-cache-control": "^1.0.1"
+ }
+ },
+ "http-response-object": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz",
+ "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==",
+ "requires": {
+ "@types/node": "^10.0.3"
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ieee754": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
+ },
+ "index.js": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/index.js/-/index.js-0.0.3.tgz",
+ "integrity": "sha1-JzOx9IbciQ7QJpiQJPWC2DXFI6w="
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "ip-regex": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
+ "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
+ },
+ "is-potential-custom-element-name": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz",
+ "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c="
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ },
+ "jmespath": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
+ "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+ },
+ "jsdom": {
+ "version": "16.2.2",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.2.2.tgz",
+ "integrity": "sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg==",
+ "requires": {
+ "abab": "^2.0.3",
+ "acorn": "^7.1.1",
+ "acorn-globals": "^6.0.0",
+ "cssom": "^0.4.4",
+ "cssstyle": "^2.2.0",
+ "data-urls": "^2.0.0",
+ "decimal.js": "^10.2.0",
+ "domexception": "^2.0.1",
+ "escodegen": "^1.14.1",
+ "html-encoding-sniffer": "^2.0.1",
+ "is-potential-custom-element-name": "^1.0.0",
+ "nwsapi": "^2.2.0",
+ "parse5": "5.1.1",
+ "request": "^2.88.2",
+ "request-promise-native": "^1.0.8",
+ "saxes": "^5.0.0",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^3.0.1",
+ "w3c-hr-time": "^1.0.2",
+ "w3c-xmlserializer": "^2.0.0",
+ "webidl-conversions": "^6.0.0",
+ "whatwg-encoding": "^1.0.5",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^8.0.0",
+ "ws": "^7.2.3",
+ "xml-name-validator": "^3.0.0"
+ },
+ "dependencies": {
+ "request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "dependencies": {
+ "tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "requires": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ }
+ }
+ },
+ "tough-cookie": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
+ "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
+ "requires": {
+ "ip-regex": "^2.1.0",
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ }
+ }
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "lodash": {
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
+ },
+ "lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg="
+ },
+ "mime-db": {
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
+ "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
+ },
+ "mime-types": {
+ "version": "2.1.24",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
+ "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
+ "requires": {
+ "mime-db": "1.40.0"
+ }
+ },
+ "moment": {
+ "version": "2.24.0",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
+ "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
+ },
+ "mysql": {
+ "version": "2.17.1",
+ "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.17.1.tgz",
+ "integrity": "sha512-7vMqHQ673SAk5C8fOzTG2LpPcf3bNt0oL3sFpxPEEFp1mdlDcrLK0On7z8ZYKaaHrHwNcQ/MTUz7/oobZ2OyyA==",
+ "requires": {
+ "bignumber.js": "7.2.1",
+ "readable-stream": "2.3.6",
+ "safe-buffer": "5.1.2",
+ "sqlstring": "2.3.1"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ }
+ }
+ },
+ "nwsapi": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
+ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ=="
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+ },
+ "optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ }
+ },
+ "package": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package/-/package-1.0.1.tgz",
+ "integrity": "sha1-0lofmeJQbcsn1nBLg9yooxLk7cw="
+ },
+ "package-lock.json": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/package-lock.json/-/package-lock.json-1.0.0.tgz",
+ "integrity": "sha512-+yEXtNdlCs5N0Zy/9uvkifgf/RqnGu0WqP4j9Wu1Us4YReFe1YNBh2Krmf8B1xGxjpYnta63K55QP8bkafnOzA=="
+ },
+ "packet-reader": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
+ "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
+ },
+ "parse-cache-control": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
+ "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104="
+ },
+ "parse5": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ },
+ "pg": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/pg/-/pg-7.12.1.tgz",
+ "integrity": "sha512-l1UuyfEvoswYfcUe6k+JaxiN+5vkOgYcVSbSuw3FvdLqDbaoa2RJo1zfJKfPsSYPFVERd4GHvX3s2PjG1asSDA==",
+ "requires": {
+ "buffer-writer": "2.0.0",
+ "packet-reader": "1.0.0",
+ "pg-connection-string": "0.1.3",
+ "pg-pool": "^2.0.4",
+ "pg-types": "^2.1.0",
+ "pgpass": "1.x",
+ "semver": "4.3.2"
+ }
+ },
+ "pg-connection-string": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz",
+ "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc="
+ },
+ "pg-int8": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
+ "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="
+ },
+ "pg-pool": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.7.tgz",
+ "integrity": "sha512-UiJyO5B9zZpu32GSlP0tXy8J2NsJ9EFGFfz5v6PSbdz/1hBLX1rNiiy5+mAm5iJJYwfCv4A0EBcQLGWwjbpzZw=="
+ },
+ "pg-types": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
+ "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
+ "requires": {
+ "pg-int8": "1.0.1",
+ "postgres-array": "~2.0.0",
+ "postgres-bytea": "~1.0.0",
+ "postgres-date": "~1.0.4",
+ "postgres-interval": "^1.1.0"
+ }
+ },
+ "pgpass": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz",
+ "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=",
+ "requires": {
+ "split": "^1.0.0"
+ }
+ },
+ "postgres-array": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
+ "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="
+ },
+ "postgres-bytea": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
+ "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU="
+ },
+ "postgres-date": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.4.tgz",
+ "integrity": "sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA=="
+ },
+ "postgres-interval": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
+ "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
+ "requires": {
+ "xtend": "^4.0.0"
+ }
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
+ "promise": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.3.tgz",
+ "integrity": "sha512-HeRDUL1RJiLhyA0/grn+PTShlBAcLuh/1BJGtrvjwbvRDCTLLMEz9rOGCV+R3vHY4MixIuoMEd9Yq/XvsTPcjw==",
+ "requires": {
+ "asap": "~2.0.6"
+ }
+ },
+ "psl": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz",
+ "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw=="
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ }
+ }
+ },
+ "request": {
+ "version": "2.88.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.0",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.4.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ }
+ },
+ "request-promise": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz",
+ "integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==",
+ "requires": {
+ "bluebird": "^3.5.0",
+ "request-promise-core": "1.1.3",
+ "stealthy-require": "^1.1.1",
+ "tough-cookie": "^2.3.3"
+ }
+ },
+ "request-promise-core": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz",
+ "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==",
+ "requires": {
+ "lodash": "^4.17.15"
+ }
+ },
+ "request-promise-native": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz",
+ "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==",
+ "requires": {
+ "request-promise-core": "1.1.3",
+ "stealthy-require": "^1.1.1",
+ "tough-cookie": "^2.3.3"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+ "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "sax": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
+ "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o="
+ },
+ "saxes": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
+ "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
+ "requires": {
+ "xmlchars": "^2.2.0"
+ }
+ },
+ "semver": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz",
+ "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c="
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "optional": true
+ },
+ "split": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+ "requires": {
+ "through": "2"
+ }
+ },
+ "sqlstring": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
+ "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A="
+ },
+ "sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "stealthy-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ }
+ }
+ },
+ "symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
+ },
+ "sync-request": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz",
+ "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==",
+ "requires": {
+ "http-response-object": "^3.0.1",
+ "sync-rpc": "^1.2.1",
+ "then-request": "^6.0.0"
+ }
+ },
+ "sync-rpc": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz",
+ "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==",
+ "requires": {
+ "get-port": "^3.1.0"
+ }
+ },
+ "then-request": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz",
+ "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==",
+ "requires": {
+ "@types/concat-stream": "^1.6.0",
+ "@types/form-data": "0.0.33",
+ "@types/node": "^8.0.0",
+ "@types/qs": "^6.2.31",
+ "caseless": "~0.12.0",
+ "concat-stream": "^1.6.0",
+ "form-data": "^2.2.0",
+ "http-basic": "^8.1.1",
+ "http-response-object": "^3.0.1",
+ "promise": "^8.0.0",
+ "qs": "^6.4.0"
+ },
+ "dependencies": {
+ "@types/node": {
+ "version": "8.10.54",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.54.tgz",
+ "integrity": "sha512-kaYyLYf6ICn6/isAyD4K1MyWWd5Q3JgH6bnMN089LUx88+s4W8GvK9Q6JMBVu5vsFFp7pMdSxdKmlBXwH/VFRg=="
+ }
+ }
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+ },
+ "tough-cookie": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ }
+ }
+ },
+ "tr46": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz",
+ "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==",
+ "requires": {
+ "punycode": "^2.1.1"
+ }
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+ },
+ "uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "url": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
+ "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
+ }
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "uuid": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
+ "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "w3c-hr-time": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
+ "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
+ "requires": {
+ "browser-process-hrtime": "^1.0.0"
+ }
+ },
+ "w3c-xmlserializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
+ "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
+ "requires": {
+ "xml-name-validator": "^3.0.0"
+ }
+ },
+ "webidl-conversions": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.0.0.tgz",
+ "integrity": "sha512-jTZAeJnc6D+yAOjygbJOs33kVQIk5H6fj9SFDOhIKjsf9HiAzL/c+tAJsc8ASWafvhNkH+wJZms47pmajkhatA=="
+ },
+ "whatwg-encoding": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
+ "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
+ "requires": {
+ "iconv-lite": "0.4.24"
+ }
+ },
+ "whatwg-mimetype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
+ "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
+ },
+ "whatwg-url": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.0.0.tgz",
+ "integrity": "sha512-41ou2Dugpij8/LPO5Pq64K5q++MnRCBpEHvQr26/mArEKTkCV5aoXIqyhuYtE0pkqScXwhf2JP57rkRTYM29lQ==",
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^2.0.0",
+ "webidl-conversions": "^5.0.0"
+ },
+ "dependencies": {
+ "webidl-conversions": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
+ "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
+ }
+ }
+ },
+ "word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
+ },
+ "ws": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz",
+ "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ=="
+ },
+ "xml-name-validator": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
+ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
+ },
+ "xml2js": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
+ "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
+ "requires": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~9.0.1"
+ }
+ },
+ "xmlbuilder": {
+ "version": "9.0.7",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
+ "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
+ },
+ "xmlchars": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
+ }
+ }
+}
diff --git a/classroomScraper/package.json b/classroomScraper/package.json
new file mode 100644
index 0000000..14feb59
--- /dev/null
+++ b/classroomScraper/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "classroommetadata",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "aws-sdk": "^2.544.0",
+ "index.js": "0.0.3",
+ "jsdom": "^16.2.2",
+ "moment": "^2.24.0",
+ "mysql": "^2.17.1",
+ "package": "^1.0.1",
+ "package-lock.json": "^1.0.0",
+ "pg": "^7.12.1",
+ "request": "^2.88.0",
+ "request-promise": "^4.2.5",
+ "sync-request": "^6.1.0"
+ }
+}
diff --git a/libHours/index.js b/libHours/index.js
new file mode 100644
index 0000000..97c206b
--- /dev/null
+++ b/libHours/index.js
@@ -0,0 +1,184 @@
+const jsdom = require("jsdom");
+const { JSDOM } = jsdom;
+var rp = require("request-promise");
+
+var AWS = require("aws-sdk");
+var Promise = require("bluebird");
+AWS.config.update({ region: "us-east-1" });
+var docClient = new AWS.DynamoDB.DocumentClient();
+
+/*
+//
+{
+ "name":"Arts Library",
+ "location":" 1400 Public Affairs Building, Los Angeles, CA 90095-1392",
+ "phone":"(310) 206-5425",
+ "image":"https://www.library.ucla.edu/sites/default/files/styles/thumbnail_large/public/location_map_images/map_arts.png?itok=0LT3XP_5",
+ "start_date":"Feb 17 ",
+ "department":
+ [
+ {
+ "department_name":"Arts Library",
+ "time":
+ [
+ {"dp_open_time":"1pm - 5pm","date":"Su 17"},
+ {"dp_open_time":"9am - 5pm","date":"M 18"},
+ {"dp_open_time":"8am - 9pm","date":"Tu 19"},
+ {"dp_open_time":"8am - 9pm","date":"W 20"},
+ {"dp_open_time":"8am - 9pm","date":"Th 21"},
+ {"dp_open_time":"8am - 5pm","date":"F 22"},
+ {"dp_open_time":"1pm - 5pm","date":"Sa 23"}
+ ]
+ },
+ {
+ "department_name":"CLICC Laptop & iPad Lending (Arts Library)",
+ "time":
+ [
+ {"dp_open_time":"1pm - 4:30pm","date":"Su 17"},
+ {"dp_open_time":"9am - 4:30pm","date":"M 18"},
+ {"dp_open_time":"8am - 8:30pm","date":"Tu 19"},
+ {"dp_open_time":"8am - 8:30pm","date":"W 20"},
+ {"dp_open_time":"8am - 8:30pm","date":"Th 21"},
+ {"dp_open_time":"8am - 4:30pm","date":"F 22"},
+ {"dp_open_time":"1pm - 4:30pm","date":"Sa 23"}
+ ]
+ },
+ {
+ "department_name":"Reference Desk",
+ "time":
+ [
+ {"dp_open_time":"Closed","date":"Su 17"},
+ {"dp_open_time":"Closed","date":"M 18"},
+ {"dp_open_time":"11am - 4pm","date":"Tu 19"},
+ {"dp_open_time":"11am - 4pm","date":"W 20"},
+ {"dp_open_time":"11am - 4pm","date":"Th 21"},
+ {"dp_open_time":"11am - 4pm","date":"F 22"},
+ {"dp_open_time":"Closed","date":"Sa 23"}]
+ }
+ ]
+}*/
+exports.handler = async function (event) {
+ try {
+ // console.log("here");
+ console.log("here");
+ //Url to visit
+ let options = {
+ method: "GET",
+ url: "https://www.library.ucla.edu/hours",
+ };
+
+ var body = await rp(options);
+ const dom = new JSDOM(body);
+
+ await new Promise((resolve) => setTimeout(resolve, 1500));
+ //find names of the 11 libraries
+ const names = dom.window.document.querySelectorAll('div.pane-node-title h2')
+ //find address of the 11 libraries
+ const addresses = dom.window.document.querySelectorAll('div.location__address')
+ //find opening times of the 11 libraries
+ const time_of_dp = dom.window.document.querySelectorAll('table.opening-hours-week')
+ //find phone number
+ const phones = dom.window.document.querySelectorAll('span.location__phone-number')
+ //find image
+ const imgs = dom.window.document.querySelectorAll('img')
+ console.log(imgs)
+ const num_rooms = names.length;
+ const data = [];
+ for (let n = 0; n < num_rooms; n++) {
+ var obj = new Object();
+ //add name to lib obj
+ const lib_name = names[n].textContent.trim()
+ obj["name"] = lib_name
+
+ //add location to lib obj
+ const lib_loc = addresses[n].textContent.trim()
+ obj["location"] = lib_loc
+ //add phone-number to lib obj
+ const lib_phone = phones[n].textContent.trim()
+ obj["phone"] = lib_phone
+ //add image to lib obj
+ const img = imgs[n + 1].src
+ obj["image"] = img
+ //add department to lib obj
+ const department = []
+ lib_dp = time_of_dp[n].textContent.trim()
+ list_dp = lib_dp.split("\n")
+ //first line : date
+ //after : openning time for each department
+ const date = list_dp[0].split('\t')
+ obj["start_date"] = date[0].split("-")[0]
+ const num_dp = list_dp.length - 1
+ for (let i = 0; i < num_dp; i++) {
+ var dp_obj = new Object();
+ dp_info = list_dp[i + 1].split('\t')
+ dp_obj["department_name"] = dp_info[0]
+
+ //console.log(list_dp[i+1].split('\t'));
+ //dp_open=dp_info[1].split(" ")
+ //dp_obj["dp_info"]=dp_info[2]
+ dp_open_time = []
+ const open_day = dp_info.length - 1
+ for (let j = 0; j < open_day; j++) {
+ var dp_time_obj = new Object();
+ dp_time_obj["dp_open_time"] = dp_info[j + 1]
+ dp_time_obj["date"] = date[j + 1]
+ dp_open_time.push(dp_time_obj);
+ }
+ dp_obj["time"] = dp_open_time
+ department.push(dp_obj);
+ }
+ obj["department"] = department
+ data.push(obj);
+ }
+
+
+ console.log(data);
+
+ var numDone = 0;
+
+ data.forEach(obj => {
+ const params = {
+ TableName: "lib_hours",
+ Key: {
+ "name": obj["name"]
+ },
+
+ UpdateExpression: "set #location = :lo, #phone = :ph, #image = :im, #start_date = :st, #department = :dp",
+
+ ExpressionAttributeNames: {
+ "#location": "location",
+ "#phone": "phone" ,
+ "#image": "image",
+ "#start_date": "start_date",
+ "#department": "department",
+ },
+
+ ExpressionAttributeValues: {
+ ":lo": obj["location"],
+ ":ph": obj["phone"],
+ ":im": obj["image"],
+ ":st": obj["start_date"],
+ ":dp": obj["department"]
+ }
+ }
+
+ docClient.update(params, function(err, data) {
+ if (err) console.log(err);
+
+ numDone += 1;
+
+ if(numDone == data.length){
+ return;
+ }
+ })
+ })
+ }
+
+ //If there is an error, write to console and exit
+ catch (err) {
+ console.error(err);
+ return;
+ }
+
+}
+// test();
diff --git a/libHours/package-lock.json b/libHours/package-lock.json
new file mode 100644
index 0000000..a8ffd11
--- /dev/null
+++ b/libHours/package-lock.json
@@ -0,0 +1,825 @@
+{
+ "name": "libhoursscraper",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "abab": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz",
+ "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w=="
+ },
+ "acorn": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
+ "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA=="
+ },
+ "acorn-globals": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz",
+ "integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==",
+ "requires": {
+ "acorn": "^6.0.1",
+ "acorn-walk": "^6.0.1"
+ }
+ },
+ "acorn-walk": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
+ "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw=="
+ },
+ "ajv": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
+ "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "array-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
+ "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM="
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ },
+ "async-limiter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
+ "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "aws-sdk": {
+ "version": "2.464.0",
+ "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.464.0.tgz",
+ "integrity": "sha512-DsJ/V/Eaazio5klO49IXIgnDpBcObgOunFs0KsUbdPz5yxvznZQiez9LqTcaj0SaCS7zsrT9K5p+Jtbt60z1SA==",
+ "requires": {
+ "buffer": "4.9.1",
+ "events": "1.1.1",
+ "ieee754": "1.1.8",
+ "jmespath": "0.15.0",
+ "querystring": "0.2.0",
+ "sax": "1.2.1",
+ "url": "0.10.3",
+ "uuid": "3.3.2",
+ "xml2js": "0.4.19"
+ }
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+ },
+ "aws4": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
+ },
+ "base64-js": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
+ "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "bluebird": {
+ "version": "3.5.5",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
+ "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w=="
+ },
+ "browser-process-hrtime": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz",
+ "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw=="
+ },
+ "buffer": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
+ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4",
+ "isarray": "^1.0.0"
+ }
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "cssom": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz",
+ "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A=="
+ },
+ "cssstyle": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz",
+ "integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==",
+ "requires": {
+ "cssom": "0.3.x"
+ }
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "data-urls": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
+ "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
+ "requires": {
+ "abab": "^2.0.0",
+ "whatwg-mimetype": "^2.2.0",
+ "whatwg-url": "^7.0.0"
+ }
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "domexception": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
+ "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
+ "requires": {
+ "webidl-conversions": "^4.0.2"
+ }
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "escodegen": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz",
+ "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==",
+ "requires": {
+ "esprima": "^3.1.3",
+ "estraverse": "^4.2.0",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1",
+ "source-map": "~0.6.1"
+ }
+ },
+ "esprima": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+ "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
+ },
+ "estraverse": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+ "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
+ },
+ "esutils": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
+ },
+ "events": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
+ "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+ },
+ "har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "requires": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "html-encoding-sniffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
+ "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
+ "requires": {
+ "whatwg-encoding": "^1.0.1"
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ieee754": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
+ "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q="
+ },
+ "ip-regex": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
+ "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ },
+ "jmespath": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
+ "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+ },
+ "jsdom": {
+ "version": "15.1.1",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.1.1.tgz",
+ "integrity": "sha512-cQZRBB33arrDAeCrAEWn1U3SvrvC8XysBua9Oqg1yWrsY/gYcusloJC3RZJXuY5eehSCmws8f2YeliCqGSkrtQ==",
+ "requires": {
+ "abab": "^2.0.0",
+ "acorn": "^6.1.1",
+ "acorn-globals": "^4.3.2",
+ "array-equal": "^1.0.0",
+ "cssom": "^0.3.6",
+ "cssstyle": "^1.2.2",
+ "data-urls": "^1.1.0",
+ "domexception": "^1.0.1",
+ "escodegen": "^1.11.1",
+ "html-encoding-sniffer": "^1.0.2",
+ "nwsapi": "^2.1.4",
+ "parse5": "5.1.0",
+ "pn": "^1.1.0",
+ "request": "^2.88.0",
+ "request-promise-native": "^1.0.7",
+ "saxes": "^3.1.9",
+ "symbol-tree": "^3.2.2",
+ "tough-cookie": "^3.0.1",
+ "w3c-hr-time": "^1.0.1",
+ "w3c-xmlserializer": "^1.1.2",
+ "webidl-conversions": "^4.0.2",
+ "whatwg-encoding": "^1.0.5",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^7.0.0",
+ "ws": "^7.0.0",
+ "xml-name-validator": "^3.0.0"
+ }
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "lodash": {
+ "version": "4.17.11",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+ },
+ "lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg="
+ },
+ "mime-db": {
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
+ "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
+ },
+ "mime-types": {
+ "version": "2.1.24",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
+ "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
+ "requires": {
+ "mime-db": "1.40.0"
+ }
+ },
+ "nwsapi": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz",
+ "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw=="
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+ },
+ "optionator": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.4",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "wordwrap": "~1.0.0"
+ }
+ },
+ "parse5": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
+ "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ=="
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ },
+ "pn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
+ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA=="
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+ },
+ "psl": {
+ "version": "1.1.32",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz",
+ "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g=="
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
+ },
+ "request": {
+ "version": "2.88.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.0",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.4.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ },
+ "tough-cookie": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ }
+ }
+ }
+ },
+ "request-promise": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.4.tgz",
+ "integrity": "sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==",
+ "requires": {
+ "bluebird": "^3.5.0",
+ "request-promise-core": "1.1.2",
+ "stealthy-require": "^1.1.1",
+ "tough-cookie": "^2.3.3"
+ },
+ "dependencies": {
+ "tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "requires": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ }
+ }
+ },
+ "request-promise-core": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz",
+ "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
+ "requires": {
+ "lodash": "^4.17.11"
+ }
+ },
+ "request-promise-native": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz",
+ "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==",
+ "requires": {
+ "request-promise-core": "1.1.2",
+ "stealthy-require": "^1.1.1",
+ "tough-cookie": "^2.3.3"
+ },
+ "dependencies": {
+ "tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "requires": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ }
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "sax": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
+ "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o="
+ },
+ "saxes": {
+ "version": "3.1.9",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.9.tgz",
+ "integrity": "sha512-FZeKhJglhJHk7eWG5YM0z46VHmI3KJpMBAQm3xa9meDvd+wevB5GuBB0wc0exPInZiBBHqi00DbS8AcvCGCFMw==",
+ "requires": {
+ "xmlchars": "^1.3.1"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "optional": true
+ },
+ "sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "stealthy-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
+ },
+ "symbol-tree": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
+ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY="
+ },
+ "tough-cookie": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
+ "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
+ "requires": {
+ "ip-regex": "^2.1.0",
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ },
+ "tr46": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+ "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "url": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
+ "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
+ }
+ }
+ },
+ "uuid": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "w3c-hr-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz",
+ "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=",
+ "requires": {
+ "browser-process-hrtime": "^0.1.2"
+ }
+ },
+ "w3c-xmlserializer": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz",
+ "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==",
+ "requires": {
+ "domexception": "^1.0.1",
+ "webidl-conversions": "^4.0.2",
+ "xml-name-validator": "^3.0.0"
+ }
+ },
+ "webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
+ },
+ "whatwg-encoding": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
+ "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
+ "requires": {
+ "iconv-lite": "0.4.24"
+ }
+ },
+ "whatwg-mimetype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
+ "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
+ },
+ "whatwg-url": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
+ "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ },
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+ },
+ "ws": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.0.0.tgz",
+ "integrity": "sha512-cknCal4k0EAOrh1SHHPPWWh4qm93g1IuGGGwBjWkXmCG7LsDtL8w9w+YVfaF+KSVwiHQKDIMsSLBVftKf9d1pg==",
+ "requires": {
+ "async-limiter": "^1.0.0"
+ }
+ },
+ "xml-name-validator": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
+ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
+ },
+ "xml2js": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
+ "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
+ "requires": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~9.0.1"
+ }
+ },
+ "xmlbuilder": {
+ "version": "9.0.7",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
+ "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
+ },
+ "xmlchars": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-1.3.1.tgz",
+ "integrity": "sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw=="
+ }
+ }
+}
diff --git a/libHours/package.json b/libHours/package.json
new file mode 100644
index 0000000..f2e6d73
--- /dev/null
+++ b/libHours/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "libhoursscraper",
+ "version": "1.0.0",
+ "description": "",
+ "main": "libraryinfo-scraper.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "aws-sdk": "^2.464.0",
+ "bluebird": "^3.5.5",
+ "jsdom": "^15.1.1",
+ "request-promise": "^4.2.4"
+ }
+}
diff --git a/libinfo-scraper.py b/libinfo-scraper.py
deleted file mode 100644
index dde6043..0000000
--- a/libinfo-scraper.py
+++ /dev/null
@@ -1,151 +0,0 @@
-import requests
-import psycopg2
-import config
-from bs4 import BeautifulSoup
-
-"""
-This module scrapes the UCLA Library Hours from the web.
-URL: https://www.library.ucla.edu/hours.
-
-Output format:
-{
- "name":"Arts Library",
- "location":" 1400 Public Affairs Building, Los Angeles, CA 90095-1392",
- "phone":"(310) 206-5425",
- "image":"https://www.library.ucla.edu/sites/default/files/styles/thumbnail_large/public/location_map_images/map_arts.png?itok=0LT3XP_5",
- "department":
- [
- {
- "department_name":"Arts Library",
- "time":
- [
- {"dp_open_time":"1pm - 5pm","date":"Su 17"},
- {"dp_open_time":"9am - 5pm","date":"M 18"},
- {"dp_open_time":"8am - 9pm","date":"Tu 19"},
- {"dp_open_time":"8am - 9pm","date":"W 20"},
- {"dp_open_time":"8am - 9pm","date":"Th 21"},
- {"dp_open_time":"8am - 5pm","date":"F 22"},
- {"dp_open_time":"1pm - 5pm","date":"Sa 23"}
- ]
- },
- {
- "department_name":"CLICC Laptop & iPad Lending (Arts Library)",
- "time":
- [
- {"dp_open_time":"1pm - 4:30pm","date":"Su 17"},
- {"dp_open_time":"9am - 4:30pm","date":"M 18"},
- {"dp_open_time":"8am - 8:30pm","date":"Tu 19"},
- {"dp_open_time":"8am - 8:30pm","date":"W 20"},
- {"dp_open_time":"8am - 8:30pm","date":"Th 21"},
- {"dp_open_time":"8am - 4:30pm","date":"F 22"},
- {"dp_open_time":"1pm - 4:30pm","date":"Sa 23"}
- ]
- },
- {
- "department_name":"Reference Desk",
- "time":
- [
- {"dp_open_time":"Closed","date":"Su 17"},
- {"dp_open_time":"Closed","date":"M 18"},
- {"dp_open_time":"11am - 4pm","date":"Tu 19"},
- {"dp_open_time":"11am - 4pm","date":"W 20"},
- {"dp_open_time":"11am - 4pm","date":"Th 21"},
- {"dp_open_time":"11am - 4pm","date":"F 22"},
- {"dp_open_time":"Closed","date":"Sa 23"}]
- }
- ]
-}
-"""
-
-
-"""
-Database schema:
-
-CREATE TABLE libraries (
- name text PRIMARY KEY,
- location text,
- phone text);
-
-CREATE TABLE library_hours (
- library_name text,
- dep_name text,
- date text,
- times text,
- FOREIGN KEY (library_name) REFERENCES libraries(name),
- PRIMARY KEY (library_name, dep_name));
-"""
-
-def get_lib_info():
-
- # get HTML data
- url = 'https://www.library.ucla.edu/hours'
- response = requests.get(url)
- if response.status_code != 200:
- print("ERROR: Could not connect to https://www.library.ucla.edu/hours")
- exit()
- page = BeautifulSoup(response.content) # Need to specify parser
-
- # loop through each library
- libraries = []
- library_hours = []
- for library in page.find_all('div', {'class': 'views-row'}):
-
- # extract library name, location, phone, & dates
- name = library.find('div', {'class': 'pane-node-title'}).find('a').text
- location = library.find('span', {'class': 'location__address-text'}).text.replace('\n', ' ').replace('\r', ' ').replace(' ', ' ').strip(' ')
- phone = library.find('span', {'class':'location__phone-number'}).text
- libraries.append((name, location, phone))
-
- # each library has multiple departments, loop through each department
- for department in library.find('tbody').find_all('tr'):
-
- # extract department name and their hours
- table = department.find_all('td')
- dep_name = table[0].text.replace('\n', ' ').replace('\r', ' ').replace(' ', ' ').strip(' ')
- for day in table[1:]:
- date = day.get('data-label')
- hours = day.text
- library_hours.append((name, dep_name, date, hours))
-
- return libraries, library_hours
-
-def main(event=None, lambda_context=None):
- # Print trigger event
- print("Triggered by:", event)
-
- # Get updated library info
- libraries, library_hours = get_lib_info()
-
- # Connect to database and insert data
- try:
- conn = psycopg2.connect(host=config.host,
- port=config.port,
- database=config.database,
- user=config.user,
- password=config.password)
- curr = conn.cursor()
- print("Connected to database.")
-
- # Remove old library data
- curr.execute("TRUNCATE libraries, library_hours CASCADE;")
-
- # Insert new library data
- sql1 = "INSERT INTO libraries(name, location, phone) VALUES (%s, %s, %s);"
- sql2 = "INSERT INTO library_hours(library_name, dep_name, date, times) VALUES (%s, %s, %s, %s);"
- curr.executemany(sql1, libraries)
- curr.executemany(sql2, library_hours)
-
- # Commit & close database
- conn.commit()
- print("Updated data in database.")
- curr.close()
- except (Exception, psycopg2.DatabaseError) as error:
- print("ERROR: ", error)
- finally:
- if conn is not None:
- conn.close()
- print('Database connection closed.')
-
-
-if __name__ == '__main__':
- main()
\ No newline at end of file
diff --git a/librarystudyrooms-scraper.js b/librarystudyrooms-scraper.js
deleted file mode 100644
index fa2221c..0000000
--- a/librarystudyrooms-scraper.js
+++ /dev/null
@@ -1,109 +0,0 @@
-const puppeteer = require('puppeteer');
-const request = require('request');
-
-/*
-JSON Format
-{
- "Building Name": "Powell Library"
- "Room Number": "Group Study Room F"
- "Capacity": 6
- "Date": "February 5, 2019"
- "Day": "Tuesday"
- "Start Time": "1:00PM"
-}
-*/
-
-(async function main() {
-
- try {
-
- const browser = await puppeteer.launch(/*{headless:false}*/);
- const [page] = await browser.pages();
- //Url to visit
- await page.goto('http://calendar.library.ucla.edu/allspaces');
-
- const result = await page.evaluate(async () => {
- //Wait for webpage to load (may need to change this 2000 ms)
- await new Promise((resolve) => setTimeout(resolve, 1500));
- const rooms = document.querySelectorAll('.s-lc-eq-avail');
- //Save length to prevent function call overhead in for loop
- const num_rooms = rooms.length;
- //Empty array to append JSON objects to
- const data = [];
-
- for (let n = 0; n < num_rooms; n++) {
- var obj = new Object();
- //Get title attribute from Anchor html elemet
- const title = rooms[n].getAttribute('title');
- //Split by commas
- var splitByCommas = title.split(",");
- //Split first element of splitByCommas array by spaces
- var timeAndDay = splitByCommas[0].split(" ");
- //Split third element of splitByCommas array by dashes
- var yearAndRoom = splitByCommas[2].split("-");
- var room = yearAndRoom[1].split(" ");
- room = room[room.length-1];
- //data.push(room);
-
- //Specific study room numbers for Powell
- if (room == 'A' || room == 'B' || room == 'C' ||
- room == 'D'|| room == 'E' || room == 'F')
- {
- obj["Building Name"] = "Powell Library";
- obj["Room"] = yearAndRoom[1].trim();
- obj["Capacity"] = 8;
- obj["Date"] = splitByCommas[1].trim() + yearAndRoom[0].trimRight();
- obj["Day"] = timeAndDay[1].trim();
- obj["Start Time"] = timeAndDay[0].trim();
- }
-
- //Specific room numbers for YRL study rooms
- else if(room == 'G01'|| room == 'G02' || room == 'G03' ||
- room == 'G04'|| room == 'G05' || room == 'G06' ||
- room == 'G07' || room == 'G08' || room == 'G09'||
- room == 'G10' || room == 'G11' || room == 'G12' ||
- room == 'G13' || room == 'G14'|| room == 'G15')
- {
- obj["Building Name"] = "Young Research Library";
- obj["Room"] = yearAndRoom[1].trim();
- obj["Capacity"] = 8;
- obj["Date"] = splitByCommas[1].trim() + yearAndRoom[0].trimRight();
- obj["Day"] = timeAndDay[1].trim();
- obj["Start Time"] = timeAndDay[0].trim();
- }
-
- //Everything else must be a study pod in YRL
- else {
- obj["Building Name"] = "Young Research Library";
- obj["Room"] = yearAndRoom[1].trim();
- obj["Capacity"] = 6;
- obj["Date"] = splitByCommas[1].trim() + yearAndRoom[0].trimRight();
- obj["Day"] = timeAndDay[1].trim();
- obj["Start Time"] = timeAndDay[0].trim();
- }
-
- //Add to data array*/
- data.push(obj);
- }
-
- return data;
- });
-
- // for (let i = 0; i < result.length; i++) {
- request.post({ url: "http://studysmart-env-2.dqiv29pdi2.us-east-1.elasticbeanstalk.com/librooms", headers: { 'content-type': 'application/json' }, body: JSON.stringify(result) }, function (err, response, body) {
- console.log(response.body)
- new Promise((resolve) => setTimeout(resolve, 10000));
- })
- // }
-
- console.log(result);
- await browser.close();
- }
-
- //If there is an error, write to console and exit
- catch (err) {
- console.error(err);
- return;
- }
-
-})();
\ No newline at end of file
diff --git a/librooms-scraper/__MACOSX/._index.js b/librooms-scraper/__MACOSX/._index.js
new file mode 100644
index 0000000..58ea31b
Binary files /dev/null and b/librooms-scraper/__MACOSX/._index.js differ
diff --git a/librooms-scraper/__MACOSX/._package.json b/librooms-scraper/__MACOSX/._package.json
new file mode 100644
index 0000000..31b7b12
Binary files /dev/null and b/librooms-scraper/__MACOSX/._package.json differ
diff --git a/librooms-scraper/__MACOSX/._test.js b/librooms-scraper/__MACOSX/._test.js
new file mode 100644
index 0000000..efe84a4
Binary files /dev/null and b/librooms-scraper/__MACOSX/._test.js differ
diff --git a/librooms-scraper/index.js b/librooms-scraper/index.js
new file mode 100644
index 0000000..ae2d2f4
--- /dev/null
+++ b/librooms-scraper/index.js
@@ -0,0 +1,468 @@
+var request = require("request");
+const moment = require("moment-timezone");
+var AWS = require("aws-sdk");
+var Promise = require("bluebird");
+var rp = require("request-promise");
+AWS.config.update({ region: "us-east-1" });
+var docClient = new AWS.DynamoDB.DocumentClient();
+
+exports.handler = async (event) => {
+
+ var now = moment().tz("America/Los_Angeles");
+ const formatString = "YYYY-MM-DD";
+ var todayString = now.format(formatString);
+ now.add(5, "days");
+ var fiveDaysLaterString = now.format(formatString);
+ var yrlOptions = {
+ method: "POST",
+ url: "http://calendar.library.ucla.edu/spaces/availability/grid", //TODO: change to https
+ headers: {
+ "cache-control": "no-cache",
+ Referer: "http://calendar.library.ucla.edu/allspaces"
+ },
+ form: {
+ lid: "5567",
+ gid: "0",
+ eid: "-1",
+ start: todayString,
+ end: fiveDaysLaterString
+ },
+ json: true
+ };
+
+ var powellOptions = {
+ method: "POST",
+ url: "http://calendar.library.ucla.edu/spaces/availability/grid", //TODO: change to https
+ headers: {
+ "cache-control": "no-cache",
+ Referer: "http://calendar.library.ucla.edu/allspaces"
+ },
+ form: {
+ lid: "4361",
+ gid: "0",
+ eid: "-1",
+ start: todayString,
+ end: fiveDaysLaterString
+ },
+ json: true
+ };
+
+ var powellInformation = await rp(powellOptions);
+ var yrlInformation = await rp(yrlOptions);
+ var powellData = [];
+ var yrlData = [];
+ for(var i = 0; i < powellInformation.length; i++)
+ {
+ if(powellInformation[i]["className"] == "s-lc-eq-checkout")
+ {
+ continue;
+ }
+ else
+ {
+ var duration = 30;
+ var obj = new Object();
+ var dateTime = powellInformation[i]["start"].split(" ");
+ var roomName;
+ var roomId = powellInformation[i]["itemId"];
+ var randomId = false;
+ switch (roomId) {
+ case 29694:
+ roomName = "Powell Group Study Room A"
+ break;
+ case 29695:
+ roomName = "Powell Group Study Room B"
+ break;
+ case 29696:
+ roomName = "Powell Group Study Room C"
+ break;
+ case 29697:
+ roomName = "Powell Group Study Room D"
+ break;
+ case 29698:
+ roomName = "Powell Group Study Room E"
+ break;
+ case 29699:
+ roomName = "Powell Group Study Room F"
+ break;
+ default:
+ randomId = true;
+ break
+ }
+ if (randomId) { continue; } // there is a random id that falsely becomes Study Room F available
+
+ obj["Building Name"] = "Powell Library";
+ obj["Room"] = roomName;
+ obj["Capacity"] = 8;
+ obj["Date"] = dateTime[0];
+ obj["Start Time"] = dateTime[1];
+ if(i+1 != powellInformation.length)
+ {
+ var dateTimeFuture = powellInformation[i]["start"].split(" ");
+ while(powellInformation[i+1]["className"] != "s-lc-eq-checkout" && dateTimeFuture[0] == dateTime[0])
+ {
+ const newDateTimeFuture = powellInformation[i+1]["start"].split(" ")
+ if (newDateTimeFuture[0] == dateTimeFuture[0]) {
+ duration += 30;
+ i++;
+ dateTimeFuture[0] = newDateTimeFuture[0];
+ dateTime[0] = newDateTimeFuture[0];
+
+ } else if (newDateTimeFuture[0] != dateTimeFuture[0] && newDateTimeFuture[1] == '00:00:00') {
+ duration += 30;
+ i++;
+ dateTimeFuture[0] = newDateTimeFuture[0];
+ dateTime[0] = newDateTimeFuture[0];
+
+ } else {
+ break;
+ }
+
+ if(i+1 == powellInformation.length)
+ break;
+ }
+ }
+ obj["Duration"] = duration.toString();
+ var item = {
+ combined: obj.Room + "," + obj["Building Name"]+ "," + obj.Capacity + ","+ obj.Date+ "," + obj.Day+ "," + obj["Start Time"]+ "," + "30",
+ room: obj.Room,
+ building: obj["Building Name"],
+ capacity: obj.Capacity,
+ date: obj.Date,
+ start: obj["Start Time"],
+ duration: obj.Duration
+ }
+ powellData.push(item);
+ }
+ }
+
+
+ var paramsPowell = {
+ TableName: "lib_rooms",
+ KeyConditionExpression: "#bd = :buildingQuery",
+ ExpressionAttributeNames: {
+ "#bd": "building",
+ },
+ ExpressionAttributeValues: {
+ ":buildingQuery": "Powell Library",
+ },
+ IndexName: "building-index",
+ ReturnConsumedCapacity: "TOTAL"
+ };
+
+ compareDatabaseData(paramsPowell, powellData);
+
+ for(var i = 0; i < yrlInformation.length; i++)
+ {
+ if(yrlInformation[i]["className"] == "s-lc-eq-checkout")
+ {
+ continue;
+ }
+ else
+ {
+ var duration = 30;
+ var obj = new Object();
+ var dateTime = yrlInformation[i]["start"].split(" ");
+ var roomName;
+ var roomId = yrlInformation[i]["itemId"];
+ var capacity = 0;
+ var randomId = false;
+ if(roomId >= 29703 && roomId <= 29718)
+ {
+ capacity = 8
+ }
+ else if(roomId <= 29738 && roomId >= 29719)
+ {
+ capacity = 6;
+ }
+ switch (roomId) {
+ case 29703:
+ roomName = "YRL Group Study Room G01"
+ break;
+ case 29704:
+ roomName = "YRL Group Study Room G02"
+ break;
+ case 29705:
+ roomName = "YRL Group Study Room G03"
+ break;
+ case 29706:
+ roomName = "YRL Group Study Room G04"
+ break;
+ case 29707:
+ roomName = "YRL Group Study Room G05"
+ break;
+ case 29708:
+ roomName = "YRL Group Study Room G06"
+ break;
+ case 29709:
+ roomName = "YRL Group Study Room G07"
+ break;
+ case 29710:
+ roomName = "YRL Group Study Room G08"
+ break;
+ case 29712:
+ roomName = "YRL Group Study Room G09"
+ break;
+ case 29713:
+ roomName = "YRL Group Study Room G10"
+ break;
+ case 29714:
+ roomName = "YRL Group Study Room G11"
+ break;
+ case 29715:
+ roomName = "YRL Group Study Room G12"
+ break;
+ case 29716:
+ roomName = "YRL Group Study Room G13"
+ break;
+ case 29717:
+ roomName = "YRL Group Study Room G14"
+ break;
+ case 29718:
+ roomName = "YRL Group Study Room G15"
+ break;
+ case 29719:
+ roomName = "YRL Collaboration Pod R01"
+ break;
+ case 29720:
+ roomName = "YRL Collaboration Pod R02"
+ break;
+ case 29721:
+ roomName = "YRL Collaboration Pod R03"
+ break;
+ case 29722:
+ roomName = "YRL Collaboration Pod R04"
+ break;
+ case 29723:
+ roomName = "YRL Collaboration Pod R05"
+ break;
+ case 29724:
+ roomName = "YRL Collaboration Pod R06"
+ break;
+ case 29725:
+ roomName = "YRL Collaboration Pod R07"
+ break;
+ case 29726:
+ roomName = "YRL Collaboration Pod R08"
+ break;
+ case 29727:
+ roomName = "YRL Collaboration Pod R09"
+ break;
+ case 29728:
+ roomName = "YRL Collaboration Pod R10"
+ break;
+ case 29729:
+ roomName = "YRL Collaboration Pod R11"
+ break;
+ case 29730:
+ roomName = "YRL Collaboration Pod R12"
+ break;
+ case 29731:
+ roomName = "YRL Collaboration Pod R13"
+ break;
+ case 29732:
+ roomName = "YRL Collaboration Pod R14"
+ break;
+ case 29733:
+ roomName = "YRL Collaboration Pod R15"
+ break;
+ case 29734:
+ roomName = "YRL Collaboration Pod R16"
+ break;
+ case 29735:
+ roomName = "YRL Collaboration Pod R17"
+ break;
+ case 29736:
+ roomName = "YRL Collaboration Pod R18"
+ break;
+ case 29737:
+ roomName = "YRL Collaboration Pod R19"
+ break;
+ case 29738:
+ roomName = "YRL Collaboration Pod R20"
+ break;
+ default:
+ randomId = true;
+ break;
+
+ }
+
+ if (randomId) {
+ continue;
+ }
+
+ obj["Building Name"] = "Young Research Library";
+ obj["Room"] = roomName;
+ obj["Capacity"] = capacity;
+ obj["Date"] = dateTime[0];
+ obj["Start Time"] = dateTime[1];
+ if(i+1 != yrlInformation.length)
+ {
+ var dateTimeFuture = yrlInformation[i]["start"].split(" ");
+ while(yrlInformation[i+1]["className"] != "s-lc-eq-checkout" && dateTimeFuture[0] == dateTime[0])
+ {
+ const newDateTimeFuture = yrlInformation[i+1]["start"].split(" ")
+ if (newDateTimeFuture[0] == dateTimeFuture[0]) {
+ duration += 30;
+ i++;
+ dateTimeFuture[0] = newDateTimeFuture[0];
+ dateTime[0] = newDateTimeFuture[0];
+ } else if (newDateTimeFuture[0] != dateTimeFuture[0] && newDateTimeFuture[1] == '00:00:00') {
+ duration += 30;
+ i++;
+ dateTimeFuture[0] = newDateTimeFuture[0]
+ dateTime[0] = newDateTimeFuture[0];
+ } else {
+ break;
+ }
+
+ if(i+1 == yrlInformation.length)
+ break;
+ }
+ }
+ obj["Duration"] = duration.toString();
+
+ var item = {
+ combined: obj.Room + "," + obj["Building Name"]+ "," + obj.Capacity + ","+ obj.Date+ "," + obj.Day+ "," + obj["Start Time"]+ "," + "30",
+ room: obj.Room,
+ building: obj["Building Name"],
+ capacity: obj.Capacity,
+ date: obj.Date,
+ start: obj["Start Time"],
+ duration: obj.Duration
+ }
+ yrlData.push(item);
+ }
+
+
+ }
+
+ var paramsYrl = {
+ TableName: "lib_rooms",
+ KeyConditionExpression: "#bd = :buildingQuery",
+ ExpressionAttributeNames: {
+ "#bd": "building",
+ },
+ ExpressionAttributeValues: {
+ ":buildingQuery": "Young Research Library",
+ },
+ IndexName: "building-index",
+ ReturnConsumedCapacity: "TOTAL"
+ };
+
+ compareDatabaseData(paramsYrl, yrlData)
+
+};
+
+function finishRequest(toAdd, toDelete) {
+
+ toAdd.forEach(info => {
+ var entry = {
+ TableName: "lib_rooms",
+ Item: info
+ };
+
+ setTimeout(
+ e => {
+ docClient.put(e, function(err, data) {
+ if (err) {
+ console.log(err);
+ }
+ });
+ },
+ 0,
+ entry
+ );
+ });
+
+ toDelete.forEach(info => {
+ var entry = {
+ TableName: "lib_rooms",
+ Key: { combined: info.combined}
+ };
+
+ setTimeout(
+ e => {
+ docClient.delete(e, function(err, data) {
+ if (err) {
+ console.log(err);
+ }
+ console.log("successfully deleted item");
+ console.log(entry);
+ });
+ },
+ 0,
+ entry
+ );
+
+ });
+}
+
+function sortFunction(a, b) {
+ if (a.combined < b.combined) return -1;
+ else return 1;
+}
+
+function compareDatabaseData(params, scrapedData) {
+
+ docClient.query(params, function(err, queryData) {
+ if (err) {
+ console.error("Unable to query. Error:", JSON.stringify(err, null, 2));
+ } else {
+ var queryItems = queryData.Items;
+
+ queryItems.sort(sortFunction);
+ scrapedData.sort(sortFunction);
+
+ console.log("queryItems");
+ console.log(queryItems);
+ console.log("scrapedItems");
+ console.log(scrapedData);
+
+ let databaseIndex = 0;
+ let scrapeIndex = 0;
+ let databaseLength = queryItems.length;
+ let scrapeLength = scrapedData.length;
+
+ let toAdd = [];
+ let toBeDeleted = [];
+
+ while (databaseIndex != databaseLength || scrapeIndex != scrapeLength) {
+ if (databaseIndex == databaseLength) {
+ toAdd.push(scrapedData[scrapeIndex]);
+ scrapeIndex++;
+ } else if (scrapeIndex == scrapeLength) {
+ toBeDeleted.push(queryItems[databaseIndex]);
+ databaseIndex++;
+ } else if (
+ queryItems[databaseIndex].combined == scrapedData[scrapeIndex].combined
+ ) {
+ const queryDuration = parseInt(queryItems[databaseIndex].duration, 10);
+ const scrapedDuration = parseInt(scrapedData[scrapeIndex].duration, 10);
+ console.log("same:", queryItems[databaseIndex].combined, queryDuration, scrapedDuration);
+ if (queryDuration == scrapedDuration) {
+ scrapeIndex++;
+ databaseIndex++;
+ } else {
+ console.log("Remove duplicate, wrong duration")
+ toBeDeleted.push(queryItems[databaseIndex]);
+ databaseIndex++;
+ toAdd.push(scrapedData[scrapeIndex]);
+ scrapeIndex++;
+ }
+ } else if (
+ queryItems[databaseIndex].combined > scrapedData[scrapeIndex].combined
+ ) {
+ toAdd.push(scrapedData[scrapeIndex]);
+ scrapeIndex++;
+ } else if (
+ queryItems[databaseIndex].combined < scrapedData[scrapeIndex].combined
+ ) {
+ toBeDeleted.push(queryItems[databaseIndex]);
+ databaseIndex++;
+ }
+ }
+ finishRequest(toAdd, toBeDeleted);
+ }
+ });
+}
+
diff --git a/librooms-scraper/package.json b/librooms-scraper/package.json
new file mode 100644
index 0000000..44540a5
--- /dev/null
+++ b/librooms-scraper/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "backend-v2",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "node scheduler.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/aseem191/backend-v2.git"
+ },
+ "author": "",
+ "license": "ISC",
+ "bugs": {
+ "url": "https://github.com/aseem191/backend-v2/issues"
+ },
+ "homepage": "https://github.com/aseem191/backend-v2#readme",
+ "dependencies": {
+ "aws-sdk": "^2.441.0",
+ "bluebird": "^3.5.4",
+ "body-parser": "^1.18.3",
+ "moment": "^2.24.0",
+ "moment-timezone": "^0.5.23",
+ "request": "^2.88.0",
+ "request-promise": "^4.2.4"
+ }
+}
diff --git a/librooms-scraper/source.html b/librooms-scraper/source.html
new file mode 100644
index 0000000..13f6588
--- /dev/null
+++ b/librooms-scraper/source.html
@@ -0,0 +1,2679 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Space Availability - Calendar - UCLA Library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Skip to Main Content
+
+
+
+
+
+
+
+ Your browser has javascript disabled. Without javascript some
+ functions will not work.
+
+
+
+
+
+
+
+
+
+
+ Please note, due to the amount of data being loaded, this page
+ can be slow to load. For a faster view, limit your search to a
+ specific Location.
+
+
+
+
CLICC Powell Spaces
+
+
+
+
+
+ Available
+
+ Your Booking
+
+ Unavailable/Padding
+
+
+
+
CLICC YRL Spaces
+
+
+
+
+
+ Available
+
+ Your Booking
+
+ Unavailable/Padding
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/librooms-scraper/test.js b/librooms-scraper/test.js
new file mode 100644
index 0000000..e1c3409
--- /dev/null
+++ b/librooms-scraper/test.js
@@ -0,0 +1,351 @@
+var request = require("request");
+const moment = require("moment-timezone");
+var AWS = require("aws-sdk");
+var Promise = require("bluebird");
+var rp = require("request-promise");
+AWS.config.update({ region: "us-east-1" });
+var docClient = new AWS.DynamoDB.DocumentClient();
+
+(async function main () {
+
+ var now = moment().tz("America/Los_Angeles");
+ const formatString = "YYYY-MM-DD";
+ var todayString = now.format(formatString);
+ now.add(5, "days");
+ var fiveDaysLaterString = now.format(formatString);
+ var yrlOptions = {
+ method: "POST",
+ url: "http://calendar.library.ucla.edu/spaces/availability/grid", //TODO: change to https
+ headers: {
+ "cache-control": "no-cache",
+ Referer: "http://calendar.library.ucla.edu/allspaces"
+ },
+ form: {
+ lid: "5567",
+ gid: "0",
+ eid: "-1",
+ start: todayString,
+ end: fiveDaysLaterString
+ },
+ json: true
+ };
+
+ var powellOptions = {
+ method: "POST",
+ url: "http://calendar.library.ucla.edu/spaces/availability/grid", //TODO: change to https
+ headers: {
+ "cache-control": "no-cache",
+ Referer: "http://calendar.library.ucla.edu/allspaces"
+ },
+ form: {
+ lid: "4361",
+ gid: "0",
+ eid: "-1",
+ start: todayString,
+ end: fiveDaysLaterString
+ },
+ json: true
+ };
+
+ var powellInformation = await rp(powellOptions);
+ var yrlInformation = await rp(yrlOptions);
+ var powellData = [];
+ var yrlData = [];
+ for(var i = 0; i < powellInformation.length; i++)
+ {
+ if(powellInformation[i]["className"] == "s-lc-eq-checkout")
+ {
+ continue;
+ }
+ else
+ {
+ var duration = 30;
+ var obj = new Object();
+ var dateTime = powellInformation[i]["start"].split(" ");
+ var roomName;
+ var roomId = powellInformation[i]["itemId"];
+ var randomId = false;
+ switch (roomId) {
+ case 29694:
+ roomName = "Powell Group Study Room A"
+ break;
+ case 29695:
+ roomName = "Powell Group Study Room B"
+ break;
+ case 29696:
+ roomName = "Powell Group Study Room C"
+ break;
+ case 29697:
+ roomName = "Powell Group Study Room D"
+ break;
+ case 29698:
+ roomName = "Powell Group Study Room E"
+ break;
+ case 29699:
+ roomName = "Powell Group Study Room F"
+ break;
+ default:
+ randomId = true;
+ }
+ if (randomId) {
+ continue;
+ }
+ obj["Building Name"] = "Powell Library";
+ obj["Room"] = roomName;
+ obj["Capacity"] = 8;
+ obj["Date"] = dateTime[0];
+ obj["Start Time"] = dateTime[1];
+ if(i+1 != powellInformation.length)
+ {
+ var dateTimeFuture = powellInformation[i]["start"].split(" ");
+ while(powellInformation[i+1]["className"] != "s-lc-eq-checkout" && dateTimeFuture[0] == dateTime[0])
+ {
+ const newDateTimeFuture = powellInformation[i+1]["start"].split(" ")
+ if (newDateTimeFuture[0] == dateTimeFuture[0]) {
+ duration += 30;
+ i++;
+ dateTimeFuture[0] = newDateTimeFuture[0];
+ dateTime[0] = newDateTimeFuture[0];
+
+ } else if (newDateTimeFuture[0] != dateTimeFuture[0] && newDateTimeFuture[1] == '00:00:00') {
+ duration += 30;
+ i++;
+ dateTimeFuture[0] = newDateTimeFuture[0];
+ dateTime[0] = newDateTimeFuture[0];
+
+ } else {
+ break;
+ }
+
+ if(i+1 == powellInformation.length)
+ break;
+ }
+ }
+ obj["Duration"] = duration.toString();
+ var item = {
+ combined: obj.Room + "," + obj["Building Name"]+ "," + obj.Capacity + ","+ obj.Date+ "," + obj.Day+ "," + obj["Start Time"]+ "," + obj.Duration,
+ room: obj.Room,
+ building: obj["Building Name"],
+ capacity: obj.Capacity,
+ date: obj.Date,
+ start: obj["Start Time"],
+ duration: obj.Duration
+ }
+ powellData.push(item);
+ }
+ }
+
+
+ var paramsPowell = {
+ TableName: "lib_rooms",
+ KeyConditionExpression: "#bd = :buildingQuery",
+ ExpressionAttributeNames: {
+ "#bd": "building",
+ },
+ ExpressionAttributeValues: {
+ ":buildingQuery": "Powell Library",
+ },
+ IndexName: "building-index",
+ ReturnConsumedCapacity: "TOTAL"
+ };
+
+// compareDatabaseData(paramsPowell, powellData);
+
+ for(var i = 0; i < yrlInformation.length; i++)
+ {
+ if(yrlInformation[i]["className"] == "s-lc-eq-checkout")
+ {
+ continue;
+ }
+ else
+ {
+ var duration = 30;
+ var obj = new Object();
+ var dateTime = yrlInformation[i]["start"].split(" ");
+ var roomName;
+ var roomId = yrlInformation[i]["itemId"];
+ var capacity = 0;
+ var randomId = false
+ if(roomId >= 29703 && roomId <= 29718)
+ {
+ capacity = 8
+ }
+ else if(roomId <= 29738 && roomId >= 29719)
+ {
+ capacity = 6;
+ }
+ switch (roomId) {
+ case 29703:
+ roomName = "YRL Group Study Room G01"
+ break;
+ case 29704:
+ roomName = "YRL Group Study Room G02"
+ break;
+ case 29705:
+ roomName = "YRL Group Study Room G03"
+ break;
+ case 29706:
+ roomName = "YRL Group Study Room G04"
+ break;
+ case 29707:
+ roomName = "YRL Group Study Room G05"
+ break;
+ case 29708:
+ roomName = "YRL Group Study Room G06"
+ break;
+ case 29709:
+ roomName = "YRL Group Study Room G07"
+ break;
+ case 29710:
+ roomName = "YRL Group Study Room G08"
+ break;
+ case 29712:
+ roomName = "YRL Group Study Room G09"
+ break;
+ case 29713:
+ roomName = "YRL Group Study Room G10"
+ break;
+ case 29714:
+ roomName = "YRL Group Study Room G11"
+ break;
+ case 29715:
+ roomName = "YRL Group Study Room G12"
+ break;
+ case 29716:
+ roomName = "YRL Group Study Room G13"
+ break;
+ case 29717:
+ roomName = "YRL Group Study Room G14"
+ break;
+ case 29718:
+ roomName = "YRL Group Study Room G15"
+ break;
+ case 29719:
+ roomName = "YRL Collaboration Pod R01"
+ break;
+ case 29720:
+ roomName = "YRL Collaboration Pod R02"
+ break;
+ case 29721:
+ roomName = "YRL Collaboration Pod R03"
+ break;
+ case 29722:
+ roomName = "YRL Collaboration Pod R04"
+ break;
+ case 29723:
+ roomName = "YRL Collaboration Pod R05"
+ break;
+ case 29724:
+ roomName = "YRL Collaboration Pod R06"
+ break;
+ case 29725:
+ roomName = "YRL Collaboration Pod R07"
+ break;
+ case 29726:
+ roomName = "YRL Collaboration Pod R08"
+ break;
+ case 29727:
+ roomName = "YRL Collaboration Pod R09"
+ break;
+ case 29728:
+ roomName = "YRL Collaboration Pod R10"
+ break;
+ case 29729:
+ roomName = "YRL Collaboration Pod R11"
+ break;
+ case 29730:
+ roomName = "YRL Collaboration Pod R12"
+ break;
+ case 29731:
+ roomName = "YRL Collaboration Pod R13"
+ break;
+ case 29732:
+ roomName = "YRL Collaboration Pod R14"
+ break;
+ case 29733:
+ roomName = "YRL Collaboration Pod R15"
+ break;
+ case 29734:
+ roomName = "YRL Collaboration Pod R16"
+ break;
+ case 29735:
+ roomName = "YRL Collaboration Pod R17"
+ break;
+ case 29736:
+ roomName = "YRL Collaboration Pod R18"
+ break;
+ case 29737:
+ roomName = "YRL Collaboration Pod R19"
+ break;
+ case 29738:
+ roomName = "YRL Collaboration Pod R20"
+ break;
+ default:
+ randomId = true;
+ break;
+
+ }
+ if (randomId) {
+ continue;
+ }
+ obj["Building Name"] = "Young Research Library";
+ obj["Room"] = roomName;
+ obj["Capacity"] = capacity;
+ obj["Date"] = dateTime[0];
+ obj["Start Time"] = dateTime[1];
+ if(i+1 != yrlInformation.length)
+ {
+ var dateTimeFuture = yrlInformation[i]["start"].split(" ");
+ while(yrlInformation[i+1]["className"] != "s-lc-eq-checkout" && dateTimeFuture[0] == dateTime[0])
+ {
+ const newDateTimeFuture = yrlInformation[i+1]["start"].split(" ")
+ if (newDateTimeFuture[0] == dateTimeFuture[0]) {
+ duration += 30;
+ i++;
+ dateTimeFuture[0] = newDateTimeFuture[0];
+ dateTime[0] = newDateTimeFuture[0];
+ } else if (newDateTimeFuture[0] != dateTimeFuture[0] && newDateTimeFuture[1] == '00:00:00') {
+ duration += 30;
+ i++;
+ dateTimeFuture[0] = newDateTimeFuture[0]
+ dateTime[0] = newDateTimeFuture[0];
+ } else {
+ break;
+ }
+
+ if(i+1 == yrlInformation.length)
+ break;
+ }
+ }
+ obj["Duration"] = duration.toString();
+
+ var item = {
+ combined: obj.Room + "," + obj["Building Name"]+ "," + obj.Capacity + ","+ obj.Date+ "," + obj.Day+ "," + obj["Start Time"]+ "," + obj.Duration,
+ room: obj.Room,
+ building: obj["Building Name"],
+ capacity: obj.Capacity,
+ date: obj.Date,
+ start: obj["Start Time"],
+ duration: obj.Duration
+ }
+ yrlData.push(item);
+ }
+
+ }
+
+ var paramsYrl = {
+ TableName: "lib_rooms",
+ KeyConditionExpression: "#bd = :buildingQuery",
+ ExpressionAttributeNames: {
+ "#bd": "building",
+ },
+ ExpressionAttributeValues: {
+ ":buildingQuery": "Young Research Library",
+ },
+ IndexName: "building-index",
+ ReturnConsumedCapacity: "TOTAL"
+ };
+
+ //compareDatabaseData(paramsYrl, yrlData)
+
+})();
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 0bf3f66..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,643 +0,0 @@
-{
- "requires": true,
- "lockfileVersion": 1,
- "dependencies": {
- "agent-base": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
- "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
- "requires": {
- "es6-promisify": "^5.0.0"
- }
- },
- "ajv": {
- "version": "6.10.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
- "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
- "requires": {
- "fast-deep-equal": "^2.0.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "asn1": {
- "version": "0.2.4",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
- "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
- "requires": {
- "safer-buffer": "~2.1.0"
- }
- },
- "assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
- },
- "async-limiter": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
- "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
- },
- "aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
- },
- "aws4": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
- "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
- },
- "balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
- },
- "bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
- "requires": {
- "tweetnacl": "^0.14.3"
- }
- },
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "buffer-from": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
- "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
- },
- "caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
- },
- "combined-stream": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
- "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
- "requires": {
- "delayed-stream": "~1.0.0"
- }
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
- },
- "concat-stream": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
- "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
- "requires": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^2.2.2",
- "typedarray": "^0.0.6"
- }
- },
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
- },
- "dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "debug": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
- "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "requires": {
- "ms": "^2.1.1"
- }
- },
- "delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
- },
- "ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
- "requires": {
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.1.0"
- }
- },
- "es6-promise": {
- "version": "4.2.6",
- "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz",
- "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q=="
- },
- "es6-promisify": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
- "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
- "requires": {
- "es6-promise": "^4.0.3"
- }
- },
- "extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
- },
- "extract-zip": {
- "version": "1.6.7",
- "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
- "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=",
- "requires": {
- "concat-stream": "1.6.2",
- "debug": "2.6.9",
- "mkdirp": "0.5.1",
- "yauzl": "2.4.1"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
- },
- "fast-deep-equal": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
- "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
- },
- "fast-json-stable-stringify": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
- "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
- },
- "fd-slicer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
- "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
- "requires": {
- "pend": "~1.2.0"
- }
- },
- "forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
- },
- "form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
- },
- "getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "glob": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
- "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
- },
- "har-validator": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
- "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
- "requires": {
- "ajv": "^6.5.5",
- "har-schema": "^2.0.0"
- }
- },
- "http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
- "requires": {
- "assert-plus": "^1.0.0",
- "jsprim": "^1.2.2",
- "sshpk": "^1.7.0"
- }
- },
- "https-proxy-agent": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
- "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
- "requires": {
- "agent-base": "^4.1.0",
- "debug": "^3.1.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
- },
- "is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
- },
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
- },
- "isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
- },
- "jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
- },
- "json-schema": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
- "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
- },
- "json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
- },
- "jsprim": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
- "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
- "requires": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.2.3",
- "verror": "1.10.0"
- }
- },
- "mime": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.2.tgz",
- "integrity": "sha512-zJBfZDkwRu+j3Pdd2aHsR5GfH2jIWhmL1ZzBoc+X+3JEti2hbArWcyJ+1laC1D2/U/W1a/+Cegj0/OnEU2ybjg=="
- },
- "mime-db": {
- "version": "1.38.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz",
- "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg=="
- },
- "mime-types": {
- "version": "2.1.22",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz",
- "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==",
- "requires": {
- "mime-db": "~1.38.0"
- }
- },
- "minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
- },
- "mkdirp": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
- "requires": {
- "minimist": "0.0.8"
- }
- },
- "ms": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
- },
- "oauth-sign": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "requires": {
- "wrappy": "1"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
- },
- "pend": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
- "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
- },
- "performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
- },
- "process-nextick-args": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
- "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
- },
- "progress": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
- "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
- },
- "proxy-from-env": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
- "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4="
- },
- "psl": {
- "version": "1.1.31",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
- "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw=="
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
- },
- "puppeteer": {
- "version": "1.14.0",
- "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.14.0.tgz",
- "integrity": "sha512-SayS2wUX/8LF8Yo2Rkpc5nkAu4Jg3qu+OLTDSOZtisVQMB2Z5vjlY2TdPi/5CgZKiZroYIiyUN3sRX63El9iaw==",
- "requires": {
- "debug": "^4.1.0",
- "extract-zip": "^1.6.6",
- "https-proxy-agent": "^2.2.1",
- "mime": "^2.0.3",
- "progress": "^2.0.1",
- "proxy-from-env": "^1.0.0",
- "rimraf": "^2.6.1",
- "ws": "^6.1.0"
- }
- },
- "qs": {
- "version": "6.5.2",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
- "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
- },
- "readable-stream": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "request": {
- "version": "2.88.0",
- "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
- "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
- "requires": {
- "aws-sign2": "~0.7.0",
- "aws4": "^1.8.0",
- "caseless": "~0.12.0",
- "combined-stream": "~1.0.6",
- "extend": "~3.0.2",
- "forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "har-validator": "~5.1.0",
- "http-signature": "~1.2.0",
- "is-typedarray": "~1.0.0",
- "isstream": "~0.1.2",
- "json-stringify-safe": "~5.0.1",
- "mime-types": "~2.1.19",
- "oauth-sign": "~0.9.0",
- "performance-now": "^2.1.0",
- "qs": "~6.5.2",
- "safe-buffer": "^5.1.2",
- "tough-cookie": "~2.4.3",
- "tunnel-agent": "^0.6.0",
- "uuid": "^3.3.2"
- }
- },
- "rimraf": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
- "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- },
- "safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "sshpk": {
- "version": "1.16.1",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
- "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
- "requires": {
- "asn1": "~0.2.3",
- "assert-plus": "^1.0.0",
- "bcrypt-pbkdf": "^1.0.0",
- "dashdash": "^1.12.0",
- "ecc-jsbn": "~0.1.1",
- "getpass": "^0.1.1",
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.0.2",
- "tweetnacl": "~0.14.0"
- }
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- },
- "tough-cookie": {
- "version": "2.4.3",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
- "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
- "requires": {
- "psl": "^1.1.24",
- "punycode": "^1.4.1"
- },
- "dependencies": {
- "punycode": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
- "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
- }
- }
- },
- "tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
- "requires": {
- "safe-buffer": "^5.0.1"
- }
- },
- "tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
- },
- "typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
- },
- "uri-js": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
- "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
- },
- "uuid": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
- "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
- },
- "verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
- "requires": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
- },
- "ws": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
- "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
- "requires": {
- "async-limiter": "~1.0.0"
- }
- },
- "yauzl": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
- "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
- "requires": {
- "fd-slicer": "~1.0.1"
- }
- }
- }
-}
diff --git a/reslife-scraper.js b/reslife-scraper.js
deleted file mode 100644
index d7f91a5..0000000
--- a/reslife-scraper.js
+++ /dev/null
@@ -1,125 +0,0 @@
-'use strict';
-
-const request = require('request');
-const jsdom = require('jsdom');
-const { JSDOM } = jsdom;
-var docClient = new AWS.DynamoDB.DocumentClient();
-/*
-JSON Format {
- "Room Details": "Sproul Study Room 110E (max 4 people)",
- "Time": "11:00pm-midnight on Sun, Mar 03",
- "Link": "https://www.orl.ucla.edu/reserve?type=sproulstudy&duration=60&date=2019-03-03&roomid=3584&start=1551682800&stop=1551686400"
-}
-*/
-async function postRequest(obj) {
- request.post({ url: "http://studysmart-env-2.dqiv29pdi2.us-east-1.elasticbeanstalk.com/studyinfo", headers: { 'content-type': 'application/json' }, body: JSON.stringify(obj) }, function (err, response, body) {
- console.log(response.body)
- new Promise((resolve) => setTimeout(resolve, 10000));
- //console.log(JSON.stringify(response.body))
- })
-}
-
-module.exports = {
- scrape: async function () {
- try {
- const browser = await puppeteer.launch({headless: false});
- const [page] = await browser.pages();
-
- await page.goto('https://reslife.ucla.edu/reserve');
-
- const result = await page.evaluate(async () => {
- const list_rooms = document.querySelectorAll('.reserve-grid .col-md-4 input').length;
- const data1 = [];
- for (let n = 0; n < list_rooms; n++) {
- const room = document.querySelectorAll('.reserve-grid .col-md-4 input').item(n);
- room.click();
- await new Promise((resolve) => setTimeout(resolve, 2000));
- const hour1 = document.querySelectorAll('.reserve-grid .col-md-6 input').item(0)
- hour1.click();
- await new Promise((resolve) => setTimeout(resolve, 2000));
- const length = document.querySelectorAll('.calendar-available').length;
- for (let j = 0; j < 7 && j < length; j++) {
- const data = [];
- const element = document.querySelectorAll('.calendar-available').item(j);
- element.click();
- await new Promise((resolve) => setTimeout(resolve, 2000));
- let columns = document.querySelectorAll('.col-md-6');
- //Get all links so that you can redirect user to registration page directly
- let links = document.getElementsByTagName('a');
- let filteredLinks = [];
- //Need to filter all links so that we only save the ones with the class mentioned below
- for (k = 0; k < links.length; k++) {
- if (links[k].getAttribute("class") == "btn btn-sm btn-block btn-default btn-select") {
- filteredLinks.push(links[k]);
- }
- }
- //Counter for filtered links
- var k = 0;
- //Start at 2 because first value is not relevant
- //Increment by 2 because every pair of 2 elements gives us "room details" and "time"
- for (i = 2; i < columns.length; i += 2) {
- //Create JS object and push required elements
- var obj = new Object();
- obj["Room Details"] = columns[i].innerText;
- obj["Time"] = columns[i + 1].innerText;
- obj["Link"] = filteredLinks[k].getAttribute("href");
- k++;
- //Push
- data.push(obj);
- }
- data1.push(data)
- }
- await new Promise((resolve) => setTimeout(resolve, 2000));
- const hour2 = document.querySelectorAll('.reserve-grid .col-md-6 input').item(1)
- hour2.click();
- await new Promise((resolve) => setTimeout(resolve, 2000));
- const length2 = document.querySelectorAll('.calendar-available').length;
- for (let j = 0; j < 7 && j < length2; j++) {
- const data = [];
- const element = document.querySelectorAll('.calendar-available').item(j);
- element.click();
- await new Promise((resolve) => setTimeout(resolve, 2000));
- let columns = document.querySelectorAll('.col-md-6');
- //Get all links so that you can redirect user to registration page directly
- let links = document.getElementsByTagName('a');
- let filteredLinks = [];
- //Need to filter all links so that we only save the ones with the class mentioned below
- for (k = 0; k < links.length; k++) {
- if (links[k].getAttribute("class") == "btn btn-sm btn-block btn-default btn-select") {
- filteredLinks.push(links[k]);
- }
- }
- //Counter for filtered links
- var k = 0;
- //Start at 2 because first value is not relevant
- //Increment by 2 because every pair of 2 elements gives us "room details" and "time"
- for (i = 2; i < columns.length; i += 2) {
- //Create JS object and push required elements
- var obj = new Object();
- obj["Room Details"] = columns[i].innerText;
- obj["Time"] = columns[i + 1].innerText;
- obj["Link"] = filteredLinks[k].getAttribute("href");
- k++;
- //Push
- data.push(obj);
- }
- data1.push(data)
- }
- }
- return data1;
- });
-
- for (let i = 0; i < result.length; i++) {
- request.post({ url: "http://studysmart-env-2.dqiv29pdi2.us-east-1.elasticbeanstalk.com/studyinfo", headers: { 'content-type': 'application/json' }, body: JSON.stringify(result[i]) }, function (err, response, body) {
- console.log(response.body)
- new Promise((resolve) => setTimeout(resolve, 10000));
- })
- }
- console.log(result);
- await browser.close();
- }
- catch (err) {
- console.error(err);
- }
-}
-}
\ No newline at end of file
diff --git a/reslife-scraper/package.json b/reslife-scraper/package.json
new file mode 100644
index 0000000..7662f0b
--- /dev/null
+++ b/reslife-scraper/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "backend-v2",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "node scheduler.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/aseem191/backend-v2.git"
+ },
+ "author": "",
+ "license": "ISC",
+ "bugs": {
+ "url": "https://github.com/aseem191/backend-v2/issues"
+ },
+ "homepage": "https://github.com/aseem191/backend-v2#readme",
+ "dependencies": {
+ "aws-sdk": "^2.441.0",
+ "bluebird": "^3.5.4",
+ "body-parser": "^1.18.3",
+ "jsdom": "^14.0.0",
+ "moment": "^2.24.0",
+ "moment-timezone": "^0.5.23",
+ "request": "^2.88.0",
+ "request-promise": "^4.2.4"
+ }
+}
diff --git a/reslife-scraper/webscraper.js b/reslife-scraper/webscraper.js
new file mode 100644
index 0000000..148f96d
--- /dev/null
+++ b/reslife-scraper/webscraper.js
@@ -0,0 +1,309 @@
+"use strict";
+
+const moment = require("moment-timezone");
+const jsdom = require("jsdom");
+const { JSDOM } = jsdom;
+var AWS = require("aws-sdk");
+var Promise = require("bluebird");
+var rp = require("request-promise");
+
+AWS.config.update({ region: "us-east-1" });
+var docClient = new AWS.DynamoDB.DocumentClient();
+/*
+JSON Format {
+ "Room Details": "Sproul Study Room 110E (max 4 people)",
+ "Time": "11:00pm-midnight on Sun, Mar 03",
+ "Link": "https://www.orl.ucla.edu/reserve?type=sproulstudy&duration=60&date=2019-03-03&roomid=3584&start=1551682800&stop=1551686400"
+}
+*/
+
+const meetingRooms = [
+ "sproulstudy",
+ "hedrick",
+ "hedrickstudy",
+ "hedrickmusic",
+ "movement",
+ "music",
+ "rieber",
+ "sproulmusic",
+ "deneve"
+];
+
+const durations = ["60", "120"];
+
+var now = moment().tz("America/Los_Angeles");
+const formatString = "YYYY-MM-DD";
+
+let next21DaysStrings = [];
+
+exports.handler = async event => {
+ let numSaturdays = 0;
+ next21DaysStrings = [];
+ now = moment().tz("America/Los_Angeles");
+ for (var i = 0; numSaturdays < 3; i++) {
+ next21DaysStrings[i] = now.format(formatString);
+
+ if (now.day() == 6) numSaturdays++;
+ now.add(1, "days");
+ }
+ for (var dayIndex = 0; dayIndex < 7; dayIndex++) {
+ for (
+ var meetingRoomIndex = 0;
+ meetingRoomIndex < meetingRooms.length;
+ meetingRoomIndex++
+ ) {
+ for (
+ var durationIndex = 0;
+ durationIndex < durations.length;
+ durationIndex++
+ ) {
+ var notResolved = true;
+ var delay = 2000;
+ while (notResolved) {
+ try {
+ var body = await sendRequest(
+ meetingRoomIndex,
+ durationIndex,
+ dayIndex,
+ delay
+ );
+ scrapeData(body, meetingRoomIndex, durationIndex, dayIndex); //TODO make async so last scrape is not dropped
+ notResolved = false;
+ } catch (e) {
+ console.log(e);
+ delay *= 2;
+ }
+ }
+ }
+ }
+ }
+};
+
+function finishRequest(toAdd, toDelete) {
+ console.log("to add: ");
+ console.log(toAdd);
+ console.log("to delete: ");
+ console.log(toDelete);
+
+ toAdd.forEach(itemValue => {
+ let params = {
+ TableName: "study_info",
+ Item: itemValue
+ };
+
+ docClient.put(params, function(err, data) {
+ if (err) {
+ //throw err;
+ console.log("error");
+ }
+ console.log("successfully put item");
+ console.log(params);
+ });
+ });
+
+ toDelete.forEach(itemValue => {
+ let params = {
+ TableName: "study_info",
+ Key: { link: itemValue.link }
+ };
+
+ docClient.delete(params, function(err, data) {
+ if (err) {
+ //throw err;
+ console.log("error");
+ }
+ console.log("successfully deleted item");
+ console.log(params);
+ });
+
+ itemValue.deletedTime = moment()
+ .tz("America/Los_Angeles")
+ .format();
+
+ params = {
+ TableName: "deleted_study_info",
+ Item: itemValue
+ };
+
+ docClient.put(params, function(err, data) {
+ if (err) {
+ //throw err;
+ console.log("error");
+ }
+ console.log(params);
+ });
+ });
+}
+
+function sortFunction(a, b) {
+ if (a.link < b.link) return -1;
+ else return 1;
+}
+
+function compareDatabaseData(params, scrapedData) {
+ docClient.query(params, function(err, queryData) {
+ if (err) {
+ console.error("Unable to query. Error:", JSON.stringify(err, null, 2));
+ } else {
+ var queryItems = queryData.Items;
+
+ queryItems.sort(sortFunction);
+ scrapedData.sort(sortFunction);
+
+ console.log("queryItems");
+ console.log(queryItems);
+
+ let databaseIndex = 0;
+ let scrapeIndex = 0;
+ let databaseLength = queryItems.length;
+ let scrapeLength = scrapedData.length;
+
+ let toAdd = [];
+ let toBeDeleted = [];
+
+ while (databaseIndex != databaseLength || scrapeIndex != scrapeLength) {
+ if (databaseIndex == databaseLength) {
+ toAdd.push(scrapedData[scrapeIndex]);
+ scrapeIndex++;
+ } else if (scrapeIndex == scrapeLength) {
+ toBeDeleted.push(queryItems[databaseIndex]);
+ databaseIndex++;
+ } else if (
+ queryItems[databaseIndex].link == scrapedData[scrapeIndex].link
+ ) {
+ scrapeIndex++;
+ databaseIndex++;
+ } else if (
+ queryItems[databaseIndex].link > scrapedData[scrapeIndex].link
+ ) {
+ toAdd.push(scrapedData[scrapeIndex]);
+ scrapeIndex++;
+ } else if (
+ queryItems[databaseIndex].link < scrapedData[scrapeIndex].link
+ ) {
+ toBeDeleted.push(queryItems[databaseIndex]);
+ databaseIndex++;
+ }
+ }
+
+ finishRequest(toAdd, toBeDeleted);
+ }
+ });
+}
+
+async function sendRequest(meetingRoomIndex, durationIndex, dayIndex, delay) {
+ let options = {
+ method: "GET",
+ url: "http://reslife.ucla.edu/reserve",
+ qs: {
+ type: meetingRooms[meetingRoomIndex],
+ duration: durations[durationIndex],
+ date: next21DaysStrings[dayIndex],
+ partial: ""
+ }
+ //timeout: 20000,
+ };
+ console.log(delay);
+ let a = new Promise(function(resolve, reject) {
+ setTimeout(() => resolve("done"), delay);
+ });
+ await a;
+ console.log("sending request");
+ console.log({
+ type: meetingRooms[meetingRoomIndex],
+ duration: durations[durationIndex],
+ date: next21DaysStrings[dayIndex]
+ });
+ return rp(options);
+}
+
+function scrapeData(body, meetingRoomIndex, durationIndex, dayIndex) {
+ const dom = new JSDOM(body);
+
+ let data = [];
+ let columns = dom.window.document.querySelectorAll(".col-md-6");
+ //Get all links so that you can redirect user to registration page directly
+ let links = dom.window.document.getElementsByTagName("a");
+ let filteredLinks = [];
+ //Need to filter all links so that we only save the ones with the class mentioned below
+ for (k = 0; k < links.length; k++) {
+ if (
+ links[k].getAttribute("class") ==
+ "btn btn-sm btn-block btn-default btn-select"
+ ) {
+ filteredLinks.push(links[k]);
+ }
+ }
+ //Counter for filtered links
+ var k = 0;
+ //Start at 2 because first value is not relevant
+ //Increment by 2 because every pair of 2 elements gives us "room details" and "time"
+
+ for (var i = 2; i < columns.length; i += 2) {
+ //Create JS object and push required elements
+ var obj = new Object();
+ obj["Room Details"] = columns[i].textContent.trim();
+ obj["Time"] = columns[i + 1].textContent.trim();
+ obj["Link"] = filteredLinks[k].getAttribute("href");
+ k++;
+
+ var splitLink = obj["Link"]
+ .split("?")
+ .join("=")
+ .split("&")
+ .join("=")
+ .split("=");
+ var infoName, infoDate, infoDuration, infoStart;
+
+ for (var linkI = 0; linkI < splitLink.length; linkI++) {
+ if (splitLink[linkI] == "type") {
+ infoName = splitLink[linkI + 1];
+ } else if (splitLink[linkI] == "date") {
+ infoDate = splitLink[linkI + 1];
+ } else if (splitLink[linkI] == "duration") {
+ infoDuration = splitLink[linkI + 1];
+ } else if (splitLink[linkI] == "start") {
+ infoStart = splitLink[linkI + 1];
+ }
+ }
+
+ var entry = {
+ link: obj["Link"],
+ name: infoName,
+ date: infoDate,
+ duration: infoDuration,
+ start: infoStart,
+ details: obj["Room Details"],
+ time: obj["Time"]
+ };
+
+ data.push(entry);
+ }
+
+ var params = {
+ TableName: "study_info",
+ KeyConditionExpression: "#dt = :dateQuery AND #nm = :nameQuery",
+ FilterExpression: "#dur = :durationFilter",
+ ExpressionAttributeNames: {
+ "#dt": "date",
+ "#nm": "name",
+ "#dur": "duration"
+ },
+ ExpressionAttributeValues: {
+ ":dateQuery": next21DaysStrings[dayIndex],
+ ":nameQuery": meetingRooms[meetingRoomIndex],
+ ":durationFilter": durations[durationIndex]
+ },
+ IndexName: "date-name-index",
+ ReturnConsumedCapacity: "TOTAL"
+ };
+ console.log("successfully scraped");
+ console.log({
+ type: meetingRooms[meetingRoomIndex],
+ duration: durations[durationIndex],
+ date: next21DaysStrings[dayIndex]
+ });
+ console.log(data);
+
+ compareDatabaseData(params, data);
+}
diff --git a/scheduler.js b/scheduler.js
deleted file mode 100644
index 5553dce..0000000
--- a/scheduler.js
+++ /dev/null
@@ -1,24 +0,0 @@
-var lib_info_scraper = require("./libraryinfo-scraper");
-var reslife_scraper = require("./reslife-scraper");
-
-var min_to_ms = 60000;
-var reslife_scraper_interval = 5 * min_to_ms;
-var lib_info_scraper_interval = 10080 * min_to_ms
-// console.log("I am doing my 5 minutes check");
-
-setInterval(function () {
- console.log("I am doing my 1 week check");
- lib_info_scraper.scrape();
- //do your stuff here
-}, lib_info_scraper_interval);
-
-setInterval(function () {
- console.log("I am doing my 5 minutes check");
- reslife_scraper.scrape();
- // do your stuff here
-}, reslife_scraper_interval);
-
-//setInterval(function () {
-// console.log("I am doing my 10 minutes check");
-// // do your stuff here
-// }, the_interval * 2);
\ No newline at end of file